@motionstudies/web 0.1.0-alpha.11 → 0.1.0-alpha.12
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/README.md
CHANGED
|
@@ -164,6 +164,28 @@ Rail and other transport consumers can share the same time filtering through `mo
|
|
|
164
164
|
|
|
165
165
|
`@motionstudies/data/air-endpoints` provides offline `enrichAirEndpoints` for existing air manifests, chunks and opening snapshots. Supply cached same-date global ADSB.lol heatmaps, an OurAirports CSV and the service date's local UTC offset. It associates only unambiguous low-altitude endpoints near a reference airport; cruise-only traces and uncertain routes stay unknown. Optional `AirEndpoint` origin/destination fields carry airport identity, observed boundary time and `observed-endpoint` evidence. `airportBoardMovements` maps full manifest entries to board rows without confusing playback chunk boundaries with flight endpoints. Input hashes and source/licence attribution are recorded in fixture metadata. These fields describe inferred observations, never flight schedules, gates or live status.
|
|
166
166
|
|
|
167
|
+
## Vehicle hero cards
|
|
168
|
+
|
|
169
|
+
`VehicleHeroCard` shows one vehicle's destination, next stop and remaining calling points. Import it from `@motionstudies/web/components/VehicleHeroCard` with `@motionstudies/web/vehicle-hero-card.css`. The **Vehicle heroes** lab compares `uk-bus` (amber onboard display), `uk-rail` (dark rail display), `yellow-bus` (yellow next-stop panel) and `sbb` (blue next-stop panel with a red service badge). These are presentation studies, not official operator components.
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<VehicleHeroCard
|
|
173
|
+
presentation="sbb"
|
|
174
|
+
vehicle={{ service: 'IC 1', operator: 'SBB CFF FFS', destination: 'Genève-Aéroport' }}
|
|
175
|
+
stops={[
|
|
176
|
+
{ id: 'bern', name: 'Bern', time: '10:28', platform: '6' },
|
|
177
|
+
{ id: 'fribourg', name: 'Fribourg/Freiburg', time: '10:56' },
|
|
178
|
+
]}
|
|
179
|
+
note="Synthetic journey · Example calls and times."
|
|
180
|
+
onSelectStop={selectStation}
|
|
181
|
+
selectedStopId={selectedStationId}
|
|
182
|
+
/>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Consumers supply remaining `stops` in journey order and update them with playback, seeking or observations; the card has no independent clock. The first supplied call is the next stop. Optional `time`, `platform` and `detail` are consumer-formatted; absent values stay absent. `vehicle.destination` is optional and shows an explicit unavailable label when missing. The final supplied stop is never inferred to be the destination: set `isDestination` only when confirmed, especially when data is progressively chunked. Empty calls mean no upcoming stops are available, without asserting that the vehicle has arrived.
|
|
186
|
+
|
|
187
|
+
The required `note` explains provenance. Optional `status`, `statusTone`, `clockLabel`, localized `labels`, `loading`, `error` and `onRetry` follow the consumer's data; the component never manufactures an on-time status. Loading and errors hide the calling points. Stop selection is controlled through stable call IDs and does not alter playback or clear when a call leaves the list. All supplied calls are shown, with wrapping names and container-based compact layouts. The lab exercises advance/rewind, unknown destinations/times, localization, disruption, recovery and narrow widths. Edition adoption requires its own package upgrade and data adapter.
|
|
188
|
+
|
|
167
189
|
## Optional live airport feed
|
|
168
190
|
|
|
169
191
|
`AirportBoard` from `@motionstudies/web/components/AirportBoard` adds Study/Now controls around an existing `AirportHeroCard` configuration. Pass `studyCard` with the usual card props and `live={{ baseUrl, edition, airport }}` for the shared service. Import `airport-hero-card.css`. `labels` localizes the wrapper's control and availability messages. The lower-level `useAirportFeed` hook and core `domain/live-airport` contract are also public exports.
|
|
@@ -193,3 +215,5 @@ The renderer now shares active GPU upload ranges, paused frame reuse, label and
|
|
|
193
215
|
`useTransitionValue(target, { durationMs, easing, steps })` from `@motionstudies/web/use-transition-value` animates a numeric value, returning `value` and `transitioning`. It reverses from the current frame, cancels on teardown, and settles immediately when reduced motion becomes active. `smoothTransition` is the default easing; `cosineTransition` and stepped progress support existing edition rhythms. Keep custom easing functions stable. Camera actions and lazy layout loading stay in the edition.
|
|
194
216
|
|
|
195
217
|
Edition chunk scripts can call `runNetworkChunkCli()` from `@motionstudies/data/network-chunk-cli`. It accepts the existing `--input`, `--manifest`, `--opening`, `--chunk-hours`, `--opening-start`, `--opening-end`, and `--focus` arguments. Source acquisition, provenance, output paths and command invocation remain edition-owned.
|
|
218
|
+
|
|
219
|
+
For timetable-backed vehicle selections, `NetworkVehicleHeroCard` from `@motionstudies/web/components/NetworkVehicleHeroCard` accepts `snapshot`, `train`, playback `time`, a required source `note` and the vehicle card's presentation/state/label options. Import `vehicle-hero-card.css`. It resolves the selected train ID against the current snapshot, retaining destination identity but showing no stale calls when that ID is absent. Calls stay in journey order, use stable journey/call IDs and follow backward seeking. During dwell the heading becomes `atStopLabel` (default “At stop”) and the time is the departure; otherwise it is the upcoming arrival. Times are formatted with `formatServiceTime` by default, without normalizing after midnight or adding delay twice. Use `showTimes={false}` for frequency-modelled journeys, and explain the model in `note`. The core `vehicleCalls` helper is also exported from `@motionstudies/core/domain/vehicle-calls` for custom adapters. Selection callback IDs refer to calls, not station indexes.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type NetworkSnapshot, type NetworkTrain } from '@motionstudies/core/domain/network';
|
|
2
|
+
import { type VehicleHeroCardProps } from './VehicleHeroCard.tsx';
|
|
3
|
+
export interface NetworkVehicleHeroCardProps extends Omit<VehicleHeroCardProps, 'vehicle' | 'stops'> {
|
|
4
|
+
readonly snapshot: NetworkSnapshot;
|
|
5
|
+
readonly train: NetworkTrain;
|
|
6
|
+
readonly time: number;
|
|
7
|
+
/** Hide clock values for frequency-based or otherwise approximate motion. */
|
|
8
|
+
readonly showTimes?: boolean;
|
|
9
|
+
readonly atStopLabel?: string;
|
|
10
|
+
readonly formatTime?: (time: number) => string;
|
|
11
|
+
}
|
|
12
|
+
/** Resolve the selected ID against the current chunk; never reuse stale stop indexes. */
|
|
13
|
+
export declare function NetworkVehicleHeroCard({ snapshot, train, time, showTimes, atStopLabel, formatTime, ...props }: NetworkVehicleHeroCardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { formatServiceTime } from '@motionstudies/core/domain/network';
|
|
4
|
+
import { vehicleCalls } from '@motionstudies/core/domain/vehicle-calls';
|
|
5
|
+
import { VehicleHeroCard } from './VehicleHeroCard.js';
|
|
6
|
+
/** Resolve the selected ID against the current chunk; never reuse stale stop indexes. */
|
|
7
|
+
export function NetworkVehicleHeroCard({ snapshot, train, time, showTimes = true, atStopLabel = 'At stop', formatTime = (value) => formatServiceTime(value).slice(0, 5), ...props }) {
|
|
8
|
+
const current = useMemo(() => snapshot.trains.find(entry => entry.id === train.id), [snapshot, train.id]);
|
|
9
|
+
const calls = current ? vehicleCalls(snapshot, current, time) : [];
|
|
10
|
+
const identity = current ?? train;
|
|
11
|
+
return _jsx(VehicleHeroCard, { ...props, vehicle: { service: identity.route || identity.shortName,
|
|
12
|
+
destination: identity.headsign.trim() || undefined }, labels: { ...props.labels, ...(calls[0]?.atStop ? { nextStop: atStopLabel } : {}) }, stops: calls.map(call => ({ ...call, time: showTimes ? formatTime(call.time) : undefined })) });
|
|
13
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export type VehicleHeroPresentation = 'uk-bus' | 'uk-rail' | 'yellow-bus' | 'sbb';
|
|
3
|
+
export interface VehicleCallingPoint {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
/** Consumer-formatted arrival time or estimate. Omit when unknown. */
|
|
7
|
+
readonly time?: string;
|
|
8
|
+
readonly platform?: string;
|
|
9
|
+
readonly detail?: string;
|
|
10
|
+
/** Set only for a confirmed destination, never just the end of a data chunk. */
|
|
11
|
+
readonly isDestination?: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare const defaultLabels: {
|
|
14
|
+
bus: string;
|
|
15
|
+
rail: string;
|
|
16
|
+
destination: string;
|
|
17
|
+
destinationUnknown: string;
|
|
18
|
+
nextStop: string;
|
|
19
|
+
callingAt: string;
|
|
20
|
+
terminus: string;
|
|
21
|
+
platform: string;
|
|
22
|
+
loading: string;
|
|
23
|
+
empty: string;
|
|
24
|
+
retry: string;
|
|
25
|
+
};
|
|
26
|
+
export interface VehicleHeroCardProps {
|
|
27
|
+
readonly vehicle: {
|
|
28
|
+
readonly service: string;
|
|
29
|
+
readonly destination?: string;
|
|
30
|
+
readonly operator?: string;
|
|
31
|
+
readonly description?: string;
|
|
32
|
+
};
|
|
33
|
+
/** Remaining calls in journey order, starting with the next stop. The consumer owns playback/filtering. */
|
|
34
|
+
readonly stops: readonly VehicleCallingPoint[];
|
|
35
|
+
readonly presentation?: VehicleHeroPresentation;
|
|
36
|
+
/** Explicit source/freshness explanation. */
|
|
37
|
+
readonly note: ReactNode;
|
|
38
|
+
readonly status?: string;
|
|
39
|
+
readonly statusTone?: 'neutral' | 'warning';
|
|
40
|
+
readonly clockLabel?: string;
|
|
41
|
+
readonly labels?: Partial<typeof defaultLabels>;
|
|
42
|
+
readonly loading?: boolean;
|
|
43
|
+
readonly error?: string;
|
|
44
|
+
readonly onRetry?: () => void;
|
|
45
|
+
readonly onSelectStop?: (id: string) => void;
|
|
46
|
+
readonly selectedStopId?: string;
|
|
47
|
+
readonly className?: string;
|
|
48
|
+
}
|
|
49
|
+
/** An onboard view of one vehicle; no destination, timing or operational status is inferred. */
|
|
50
|
+
export declare function VehicleHeroCard({ vehicle, stops, presentation, note, status, statusTone, clockLabel, labels, loading, error, onRetry, onSelectStop, selectedStopId, className }: VehicleHeroCardProps): import("react").JSX.Element;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
const defaultLabels = {
|
|
4
|
+
bus: 'Bus', rail: 'Train', destination: 'Destination', destinationUnknown: 'Destination unavailable',
|
|
5
|
+
nextStop: 'Next stop', callingAt: 'Then calling at', terminus: 'Destination', platform: 'Platform',
|
|
6
|
+
loading: 'Loading upcoming stops…', empty: 'No upcoming stops available.', retry: 'Retry',
|
|
7
|
+
};
|
|
8
|
+
/** An onboard view of one vehicle; no destination, timing or operational status is inferred. */
|
|
9
|
+
export function VehicleHeroCard({ vehicle, stops, presentation = 'uk-rail', note, status, statusTone = 'neutral', clockLabel, labels, loading, error, onRetry, onSelectStop, selectedStopId, className = '' }) {
|
|
10
|
+
const titleId = useId();
|
|
11
|
+
const copy = { ...defaultLabels, ...labels };
|
|
12
|
+
const bus = presentation === 'uk-bus' || presentation === 'yellow-bus';
|
|
13
|
+
const [next, ...following] = stops;
|
|
14
|
+
const stopContent = (stop) => _jsxs(_Fragment, { children: [_jsxs("span", { className: "ms-vehicle-hero__stop-name", children: [stop.name, stop.isDestination && _jsx("small", { children: copy.terminus }), stop.detail && _jsx("span", { className: "ms-vehicle-hero__detail", children: stop.detail })] }), (stop.time || stop.platform) && _jsxs("span", { className: "ms-vehicle-hero__timing", children: [stop.time && _jsx("strong", { children: stop.time }), stop.platform && _jsxs("small", { children: [copy.platform, " ", stop.platform] })] })] });
|
|
15
|
+
const renderStop = (stop) => onSelectStop
|
|
16
|
+
? _jsx("button", { type: "button", className: "ms-vehicle-hero__stop", "aria-pressed": selectedStopId === stop.id, onClick: () => onSelectStop(stop.id), children: stopContent(stop) })
|
|
17
|
+
: _jsx("div", { className: "ms-vehicle-hero__stop", children: stopContent(stop) });
|
|
18
|
+
return _jsxs("section", { className: `ms-vehicle-hero ${className}`, "data-presentation": presentation, "aria-labelledby": titleId, "aria-busy": loading || undefined, children: [_jsxs("div", { className: "ms-vehicle-hero__masthead", children: [_jsxs("span", { children: [bus ? copy.bus : copy.rail, vehicle.operator ? ` · ${vehicle.operator}` : ''] }), clockLabel && _jsx("span", { children: clockLabel })] }), _jsxs("div", { className: "ms-vehicle-hero__identity", children: [_jsx("strong", { className: "ms-vehicle-hero__service", children: vehicle.service }), _jsxs("div", { children: [_jsx("p", { className: "ms-vehicle-hero__eyebrow", children: copy.destination }), _jsx("h2", { id: titleId, children: vehicle.destination || copy.destinationUnknown }), vehicle.description && _jsx("p", { className: "ms-vehicle-hero__description", children: vehicle.description })] })] }), status && _jsx("div", { className: "ms-vehicle-hero__status", "data-tone": statusTone, children: status }), error ? _jsxs("div", { className: "ms-vehicle-hero__message", role: "status", children: [error, onRetry && _jsx("button", { type: "button", onClick: onRetry, children: copy.retry })] })
|
|
19
|
+
: loading ? _jsx("div", { className: "ms-vehicle-hero__message", role: "status", children: copy.loading })
|
|
20
|
+
: next ? _jsxs("div", { className: "ms-vehicle-hero__journey", children: [_jsxs("div", { className: "ms-vehicle-hero__next", children: [_jsx("p", { className: "ms-vehicle-hero__eyebrow", children: copy.nextStop }), renderStop(next)] }), following.length > 0 && _jsxs("div", { className: "ms-vehicle-hero__following", children: [_jsx("p", { className: "ms-vehicle-hero__eyebrow", children: copy.callingAt }), _jsx("ol", { children: following.map((stop) => _jsx("li", { "data-terminus": stop.isDestination || undefined, children: renderStop(stop) }, stop.id)) })] })] }) : _jsx("div", { className: "ms-vehicle-hero__message", role: "status", children: copy.empty }), _jsx("div", { className: "ms-vehicle-hero__note", children: note })] });
|
|
21
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
.ms-vehicle-hero {
|
|
2
|
+
--vehicle-bg: #101820; --vehicle-panel: #070b10; --vehicle-ink: #f1b94f;
|
|
3
|
+
--vehicle-text: #f4f4ed; --vehicle-muted: #a9b2ba; --vehicle-line: #33404b;
|
|
4
|
+
--vehicle-badge: #183b55; --vehicle-badge-ink: #fff;
|
|
5
|
+
container-type: inline-size; width: 100%; min-width: 0; overflow: hidden;
|
|
6
|
+
border: 1px solid var(--vehicle-line); border-radius: 8px;
|
|
7
|
+
background: var(--vehicle-bg); color: var(--vehicle-text); font: 16px/1.4 Arial, Helvetica, sans-serif;
|
|
8
|
+
}
|
|
9
|
+
.ms-vehicle-hero, .ms-vehicle-hero * { box-sizing: border-box; }
|
|
10
|
+
.ms-vehicle-hero[data-presentation="uk-bus"] {
|
|
11
|
+
--vehicle-bg: #1a201d; --vehicle-panel: #080d09; --vehicle-ink: #ffbd59;
|
|
12
|
+
--vehicle-badge: #ffbd59; --vehicle-badge-ink: #10150e; --vehicle-line: #3c473d;
|
|
13
|
+
}
|
|
14
|
+
.ms-vehicle-hero[data-presentation="sbb"] {
|
|
15
|
+
--vehicle-bg: #fff; --vehicle-panel: #123579; --vehicle-ink: #fff; --vehicle-text: #162846;
|
|
16
|
+
--vehicle-muted: #54647c; --vehicle-line: #d5dce6; --vehicle-badge: #eb0000; --vehicle-badge-ink: #fff;
|
|
17
|
+
border-radius: 2px;
|
|
18
|
+
}
|
|
19
|
+
.ms-vehicle-hero[data-presentation="yellow-bus"] {
|
|
20
|
+
--vehicle-bg: #fffcf3; --vehicle-panel: #ffdc00; --vehicle-ink: #202318; --vehicle-text: #202318;
|
|
21
|
+
--vehicle-muted: #62624e; --vehicle-line: #d9d5bd; --vehicle-badge: #202318; --vehicle-badge-ink: #ffdc00;
|
|
22
|
+
border-radius: 2px;
|
|
23
|
+
}
|
|
24
|
+
.ms-vehicle-hero__masthead { display: flex; justify-content: space-between; gap: 12px; padding: 15px 24px; color: var(--vehicle-muted); font-size: 12px; font-variant-numeric: tabular-nums; border-bottom: 1px solid var(--vehicle-line); }
|
|
25
|
+
.ms-vehicle-hero__masthead span { overflow-wrap: anywhere; }
|
|
26
|
+
.ms-vehicle-hero__identity { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 20px; padding: 28px 24px; }
|
|
27
|
+
.ms-vehicle-hero__service { background: var(--vehicle-badge); color: var(--vehicle-badge-ink); font-size: clamp(22px, 6cqi, 36px); padding: 8px 12px; line-height: 1.1; max-width: 160px; overflow-wrap: anywhere; }
|
|
28
|
+
.ms-vehicle-hero__eyebrow { margin: 0 0 8px; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; font-weight: 600; }
|
|
29
|
+
.ms-vehicle-hero__identity h2 { margin: 0; font-size: clamp(24px, 5.5cqi, 38px); line-height: 1.12; letter-spacing: -.035em; overflow-wrap: anywhere; font-weight: 600; }
|
|
30
|
+
.ms-vehicle-hero__description { color: var(--vehicle-muted); font-size: 13px; margin: 10px 0 0; overflow-wrap: anywhere; }
|
|
31
|
+
.ms-vehicle-hero__status { margin: 0 24px 20px; padding: 9px 12px; border-left: 3px solid var(--vehicle-muted); font-size: 13px; overflow-wrap: anywhere; }
|
|
32
|
+
.ms-vehicle-hero__status[data-tone="warning"] { border-color: #c87d00; background: #ffe6ae; color: #493000; }
|
|
33
|
+
.ms-vehicle-hero__next { background: var(--vehicle-panel); color: var(--vehicle-ink); padding: 20px 24px 24px; }
|
|
34
|
+
.ms-vehicle-hero__next .ms-vehicle-hero__stop-name { font-size: clamp(23px, 5cqi, 34px); line-height: 1.16; }
|
|
35
|
+
.ms-vehicle-hero[data-presentation^="uk-"] .ms-vehicle-hero__next { font-family: ui-monospace, 'SFMono-Regular', Consolas, monospace; }
|
|
36
|
+
.ms-vehicle-hero__stop { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 8px 0; min-width: 0; width: 100%; text-align: left; color: inherit; font: inherit; }
|
|
37
|
+
.ms-vehicle-hero button.ms-vehicle-hero__stop { border: 0; border-radius: 0; background: none; cursor: pointer; }
|
|
38
|
+
.ms-vehicle-hero button.ms-vehicle-hero__stop:hover { box-shadow: 0 1px currentColor; }
|
|
39
|
+
.ms-vehicle-hero button.ms-vehicle-hero__stop[aria-pressed="true"] { box-shadow: 0 2px currentColor; }
|
|
40
|
+
.ms-vehicle-hero button:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
|
|
41
|
+
.ms-vehicle-hero__stop-name { min-width: 0; overflow-wrap: anywhere; font-size: 17px; font-weight: 600; }
|
|
42
|
+
.ms-vehicle-hero__stop small, .ms-vehicle-hero__detail { display: block; font: 12px/1.5 Arial, Helvetica, sans-serif; margin-top: 5px; }
|
|
43
|
+
.ms-vehicle-hero__timing { flex-shrink: 0; max-width: 40%; text-align: right; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
|
|
44
|
+
.ms-vehicle-hero__timing strong { font-size: 16px; font-weight: 500; }
|
|
45
|
+
.ms-vehicle-hero__following { padding: 24px; }
|
|
46
|
+
.ms-vehicle-hero__following > p { color: var(--vehicle-muted); }
|
|
47
|
+
.ms-vehicle-hero__following ol { list-style: none; padding: 0 0 0 20px; margin: 14px 0 0; }
|
|
48
|
+
.ms-vehicle-hero__following li { position: relative; padding: 2px 0 14px 14px; border-left: 2px solid var(--vehicle-line); }
|
|
49
|
+
.ms-vehicle-hero__following li:last-child { padding-bottom: 0; border-color: transparent; }
|
|
50
|
+
.ms-vehicle-hero__following li:last-child::after { content: ''; position: absolute; left: -2px; top: 0; width: 2px; height: 18px; background: var(--vehicle-line); }
|
|
51
|
+
.ms-vehicle-hero__following li::before { content: ''; position: absolute; width: 9px; height: 9px; border: 2px solid var(--vehicle-text); background: var(--vehicle-bg); border-radius: 50%; left: -5.5px; top: 18px; }
|
|
52
|
+
.ms-vehicle-hero__following li[data-terminus]::before { background: var(--vehicle-text); }
|
|
53
|
+
.ms-vehicle-hero__message { padding: 28px 24px; min-height: 120px; display: flex; flex-wrap: wrap; align-items: center; gap: 16px; overflow-wrap: anywhere; }
|
|
54
|
+
.ms-vehicle-hero__message button { padding: 8px 12px; border: 1px solid currentColor; color: inherit; background: transparent; font: inherit; cursor: pointer; }
|
|
55
|
+
.ms-vehicle-hero__note { padding: 16px 24px; border-top: 1px solid var(--vehicle-line); color: var(--vehicle-muted); font-size: 11px; line-height: 1.6; overflow-wrap: anywhere; }
|
|
56
|
+
@container (max-width: 360px) {
|
|
57
|
+
.ms-vehicle-hero__identity { gap: 12px; padding: 22px 16px; }
|
|
58
|
+
.ms-vehicle-hero__service { max-width: 100px; padding: 8px; }
|
|
59
|
+
.ms-vehicle-hero__masthead, .ms-vehicle-hero__next, .ms-vehicle-hero__following, .ms-vehicle-hero__note, .ms-vehicle-hero__message { padding-left: 16px; padding-right: 16px; }
|
|
60
|
+
.ms-vehicle-hero__status { margin-left: 16px; margin-right: 16px; }
|
|
61
|
+
.ms-vehicle-hero__stop { gap: 10px; }
|
|
62
|
+
.ms-vehicle-hero__next .ms-vehicle-hero__stop { flex-wrap: wrap; }
|
|
63
|
+
.ms-vehicle-hero__next .ms-vehicle-hero__timing { max-width: 100%; text-align: left; }
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motionstudies/web",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Browser controls and loaders for Motion Studies.",
|
|
@@ -121,6 +121,12 @@
|
|
|
121
121
|
"import": "./components/BusStopHeroCard.js",
|
|
122
122
|
"default": "./components/BusStopHeroCard.js"
|
|
123
123
|
},
|
|
124
|
+
"./components/VehicleHeroCard": {
|
|
125
|
+
"types": "./components/VehicleHeroCard.d.ts",
|
|
126
|
+
"import": "./components/VehicleHeroCard.js",
|
|
127
|
+
"default": "./components/VehicleHeroCard.js"
|
|
128
|
+
},
|
|
129
|
+
"./vehicle-hero-card.css": "./components/vehicle-hero-card.css",
|
|
124
130
|
"./components/RailStationHeroCard": {
|
|
125
131
|
"types": "./components/RailStationHeroCard.d.ts",
|
|
126
132
|
"import": "./components/RailStationHeroCard.js",
|
|
@@ -136,6 +142,11 @@
|
|
|
136
142
|
"types": "./use-transition-value.d.ts",
|
|
137
143
|
"import": "./use-transition-value.js",
|
|
138
144
|
"default": "./use-transition-value.js"
|
|
145
|
+
},
|
|
146
|
+
"./components/NetworkVehicleHeroCard": {
|
|
147
|
+
"types": "./components/NetworkVehicleHeroCard.d.ts",
|
|
148
|
+
"import": "./components/NetworkVehicleHeroCard.js",
|
|
149
|
+
"default": "./components/NetworkVehicleHeroCard.js"
|
|
139
150
|
}
|
|
140
151
|
},
|
|
141
152
|
"files": [
|
|
@@ -151,7 +162,7 @@
|
|
|
151
162
|
"**/*.css"
|
|
152
163
|
],
|
|
153
164
|
"dependencies": {
|
|
154
|
-
"@motionstudies/core": "0.1.0-alpha.
|
|
165
|
+
"@motionstudies/core": "0.1.0-alpha.12"
|
|
155
166
|
},
|
|
156
167
|
"peerDependencies": {
|
|
157
168
|
"react": "^19.2.8",
|