Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tweak: Resize editable directions textbox #2883

Merged
merged 11 commits into from
Oct 31, 2024
Merged
28 changes: 28 additions & 0 deletions assets/css/_autosized_textarea.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.c-autosized-textarea {
display: grid;
// The main area that the textarea and the "'Sizer" occupy
grid-template-areas: "slot";

&::after, // "Sizer"
> textarea {
grid-area: slot;
}

&::after {
content: attr(data-replicated-value) " ";
white-space: pre-wrap;
visibility: hidden;
}
> textarea {
resize: none;
overflow: hidden;
}
&::after,
> textarea {
border: 1px solid $list-group-border-color;
padding: 0.5rem;
font: inherit;
margin-bottom: 1rem;
line-height: 1.5rem;
}
}
1 change: 1 addition & 0 deletions assets/css/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ $vpp-location-padding: 1rem;
@import "leaflet";
@import "skate_ui";

@import "autosized_textarea";
@import "basic_notification_modal";
@import "circle_x_icon";
@import "card";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import inTestGroup, { TestGroups } from "../../../userInTestGroup"

export interface ActiveDetourPanelProps extends PropsWithChildren {
detourText: string
copyableDetourText: string
directions?: DetourDirection[]
connectionPoints?: [string, string]
missedStops?: Stop[]
Expand All @@ -30,7 +30,7 @@ export interface ActiveDetourPanelProps extends PropsWithChildren {
}

export const ActiveDetourPanel = ({
detourText,
copyableDetourText,
directions,
connectionPoints,
missedStops,
Expand Down Expand Up @@ -63,7 +63,7 @@ export const ActiveDetourPanel = ({
{backButton}
{/* TODO: temporary test group until I get the copy logic hooked up */}
{inTestGroup(TestGroups.CopyButton) && (
<CopyButton detourText={detourText} />
<CopyButton detourText={copyableDetourText} />
)}
</Panel.Header>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,37 @@ import React, { PropsWithChildren } from "react"
import { Button, Form } from "react-bootstrap"
import * as BsIcons from "../../../helpers/bsIcons"
import { Panel } from "../diversionPage"
import { CopyButton } from "../detourPanelComponents"
import {
ConnectionPoints,
CopyButton,
MissedStops,
} from "../detourPanelComponents"
import { Stop } from "../../../schedule"

interface DetourFinishedPanelProps extends PropsWithChildren {
onNavigateBack: () => void
detourText: string
copyableDetourText: string
editableDirections: string
connectionPoints?: [string, string]
missedStops?: Stop[]
onChangeDetourText: (value: string) => void
onActivateDetour?: () => void
}

export const DetourFinishedPanel = ({
onNavigateBack,
detourText,
copyableDetourText,
editableDirections,
connectionPoints,
missedStops,
onChangeDetourText,
onActivateDetour,
children,
}: DetourFinishedPanelProps) => (
<Panel as="article" className="c-diversion-panel">
<Panel.Header>
<h1 className="c-diversion-panel__h1 my-3">View Draft Detour</h1>
<CopyButton detourText={detourText} />
<CopyButton detourText={copyableDetourText} />
</Panel.Header>

<Panel.Body className="d-flex flex-column">
Expand All @@ -35,15 +46,32 @@ export const DetourFinishedPanel = ({
<BsIcons.ArrowLeft /> Edit
</Button>

<Form.Control
as="textarea"
value={detourText}
onChange={({ target: { value } }) => onChangeDetourText(value)}
className="flex-grow-1 mb-3"
style={{
resize: "none",
}}
/>
<h2 className="c-diversion-panel__h2">Directions</h2>
{/*
We need a way to let the form area take up exactly the space of its content
(to avoid double scrollbars). We used this approach:
https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas

The result is that the Form.Control has an invisible twin that helps the
wrapper grow to the appropriate size, and then the Form.Control likewise
assumes that space. All formatting between the Form.Control and the ::after
pseudo-element must be identical: border, padding, margin, font.
hannahpurcell marked this conversation as resolved.
Show resolved Hide resolved
*/}
<div
className="c-autosized-textarea"
data-replicated-value={editableDirections}
>
<Form.Control
as="textarea"
value={editableDirections}
onChange={({ target: { value } }) => onChangeDetourText(value)}
/>
</div>

{connectionPoints && (
<ConnectionPoints connectionPoints={connectionPoints} />
)}
{missedStops && <MissedStops missedStops={missedStops} />}
</Panel.Body.ScrollArea>

<Panel.Body.Footer className="d-flex flex-column">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import inTestGroup, { TestGroups } from "../../../userInTestGroup"

export interface PastDetourPanelProps {
detourText: string
copyableDetourText: string
directions?: DetourDirection[]
connectionPoints: [string, string]
missedStops?: Stop[]
Expand All @@ -25,7 +25,7 @@ export interface PastDetourPanelProps {
}

export const PastDetourPanel = ({
detourText,
copyableDetourText,
directions,
connectionPoints,
missedStops,
Expand All @@ -40,7 +40,7 @@ export const PastDetourPanel = ({
<h1 className="c-diversion-panel__h1 my-3">View Past Detour</h1>
{/* TODO: temporary test group until I get the copy logic hooked up */}
{inTestGroup(TestGroups.CopyButton) && (
<CopyButton detourText={detourText} />
<CopyButton detourText={copyableDetourText} />
)}
</Panel.Header>

Expand Down
63 changes: 27 additions & 36 deletions assets/src/components/detours/diversionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import React, {
ComponentPropsWithoutRef,
PropsWithChildren,
useContext,
useEffect,
useState,
} from "react"
import { DrawDetourPanel } from "./detourPanels/drawDetourPanel"
Expand Down Expand Up @@ -113,16 +112,15 @@ export const DiversionPage = ({
: { input: useDetourProps.originalRoute }
)

const [textArea, setTextArea] = useState("")

const nearestIntersectionDirection = [
{ instruction: "From " + nearestIntersection },
]
const extendedDirections = directions
? nearestIntersectionDirection.concat(directions)
: undefined

const { route, routePattern, routePatterns } = snapshot.context
const { route, routePattern, routePatterns, editedDirections } =
snapshot.context
const routePatternsById = Object.fromEntries(
routePatterns?.map((rp) => [rp.id, rp]) ?? []
)
Expand All @@ -137,35 +135,20 @@ export const DiversionPage = ({
? displayFieldsFromRouteAndPattern(route, routePattern)
: {}

useEffect(() => {
if (snapshot.matches({ "Detour Drawing": "Share Detour" })) {
setTextArea(
[
`Detour ${routeName} ${routeDirection}`,
routeOrigin,
,
"Connection Points:",
connectionPoints?.start?.name ?? "N/A",
connectionPoints?.end?.name ?? "N/A",
,
`Missed Stops (${missedStops?.length}):`,
...(missedStops?.map(({ name }) => name) ?? ["no stops"]),
,
"Turn-by-Turn Directions:",
...(extendedDirections?.map((v) => v.instruction) ?? []),
].join("\n")
)
}
}, [
snapshot,
routeName,
routeDirection,
const copyableDetourText = [
`Detour ${routeName} ${routeDirection}`,
routeOrigin,
extendedDirections,
missedStops,
connectionPoints?.start?.name,
connectionPoints?.end?.name,
])
,
"Connection Points:",
connectionPoints?.start?.name ?? "N/A",
connectionPoints?.end?.name ?? "N/A",
,
`Missed Stops (${missedStops?.length}):`,
...(missedStops?.map(({ name }) => name) ?? ["no stops"]),
,
"Turn-by-Turn Directions:",
...(extendedDirections?.map((v) => v.instruction) ?? []),
].join("\n")

const routes = useContext(RoutesContext)
const epochNowInSeconds = useCurrentTimeSeconds()
Expand Down Expand Up @@ -260,8 +243,16 @@ export const DiversionPage = ({
return (
<DetourFinishedPanel
onNavigateBack={editDetour}
detourText={textArea}
onChangeDetourText={setTextArea}
copyableDetourText={copyableDetourText}
editableDirections={editedDirections || ""}
connectionPoints={[
connectionPoints?.start?.name ?? "N/A",
connectionPoints?.end?.name ?? "N/A",
]}
missedStops={missedStops}
onChangeDetourText={(detourText: string) =>
send({ type: "detour.share.edit-directions", detourText })
}
onActivateDetour={
inTestGroup(TestGroups.DetoursList)
? () => {
Expand Down Expand Up @@ -345,7 +336,7 @@ export const DiversionPage = ({
} else if (snapshot.matches({ "Detour Drawing": "Active" })) {
return (
<ActiveDetourPanel
detourText="Hello World"
copyableDetourText={copyableDetourText}
directions={extendedDirections}
connectionPoints={[
connectionPoints?.start?.name ?? "N/A",
Expand Down Expand Up @@ -386,7 +377,7 @@ export const DiversionPage = ({
} else if (snapshot.matches({ "Detour Drawing": "Past" })) {
return (
<PastDetourPanel
detourText="Hello World"
copyableDetourText={copyableDetourText}
directions={extendedDirections}
connectionPoints={[
connectionPoints?.start?.name ?? "N/A",
Expand Down
24 changes: 23 additions & 1 deletion assets/src/models/createDetourMachine.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { setup, assign, fromPromise, ActorLogicFrom, InputFrom } from "xstate"
import { RoutePatternId, ShapePoint } from "../schedule"
import { Route, RouteId, RoutePattern } from "../schedule"
import { Ok, Result } from "../util/result"
import { isOk, Ok, Result } from "../util/result"
import {
FetchDetourDirectionsError,
fetchDetourDirections,
Expand Down Expand Up @@ -30,6 +30,8 @@ export const createDetourMachine = setup({

finishedDetour: FinishedDetour | undefined | null

editedDirections?: string

selectedDuration?: string
selectedReason?: string
},
Expand Down Expand Up @@ -66,6 +68,7 @@ export const createDetourMachine = setup({
| { type: "detour.edit.place-waypoint-on-route"; location: ShapePoint }
| { type: "detour.edit.place-waypoint"; location: ShapePoint }
| { type: "detour.edit.undo" }
| { type: "detour.share.edit-directions"; detourText: string }
| { type: "detour.share.copy-detour"; detourText: string }
| { type: "detour.share.open-activate-modal" }
| {
Expand Down Expand Up @@ -472,6 +475,19 @@ export const createDetourMachine = setup({

onDone: {
target: "Share Detour",
actions: assign({
editedDirections: ({ context }) => {
const detourShape =
context.detourShape && isOk(context.detourShape)
? context.detourShape.ok
: null

return [
"From " + context.nearestIntersection,
...(detourShape?.directions?.map((v) => v.instruction) ?? []),
].join("\n")
},
}),
},
},
"Share Detour": {
Expand All @@ -490,6 +506,12 @@ export const createDetourMachine = setup({
"detour.share.open-activate-modal": {
target: "Activating",
},
"detour.share.edit-directions": {
target: "Reviewing",
actions: assign({
editedDirections: ({ event }) => event.detourText,
}),
},
},
},
Activating: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,12 @@ import React from "react"
import { ActiveDetourPanel } from "../../../src/components/detours/detourPanels/activeDetourPanel"
import { stopFactory } from "../../../tests/factories/stop"

const defaulText = [
"Detour:",
"66 Harvard via Allston from",
"Andrew Station",
"Outbound",
"",
"Turn-by-Turn Directions:",
const defaultText = [
"Start at Centre St & John St",
"Right on John St",
"Left on Abbotsford Rd",
"Right on Boston St",
"Regular Route",
"",
"Connection Points:",
"Centre St & John St",
"Boston St",
"",
"Missed Stops (3):",
"Example St @ Sample Ave",
"Example St opp Random Way",
"Example St @ Fake Blvd",
].join("\n")

const meta = {
Expand All @@ -34,7 +19,7 @@ const meta = {
stretch: true,
},
args: {
detourText: defaulText,
copyableDetourText: defaultText,
directions: [
{ instruction: "Start at Centre St & John St" },
{ instruction: "Right on John St" },
Expand Down
Loading
Loading