Skip to content

Commit

Permalink
moving forward
Browse files Browse the repository at this point in the history
  • Loading branch information
alexreardon committed May 7, 2018
1 parent 0f1fa90 commit ed8a743
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 385 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
"react-redux": "^5.0.7",
"redux": "^4.0.0",
"redux-thunk": "^2.2.0",
"reselect": "^3.0.1",
"tiny-invariant": "^0.0.3"
},
"devDependencies": {
Expand Down
112 changes: 35 additions & 77 deletions src/state/dimension-marshal/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import type {
DraggableDescriptor,
ScrollOptions,
Viewport,
DroppableDimensionMap,
DraggableDimensionMap,
DimensionMap,
} from '../../types';
import type {
Entries,
Expand All @@ -20,48 +23,35 @@ import type {
Collection,
} from './dimension-marshal-types';

export type Collector = {|
start: (collection: Collection) => void,
stop: () => void,
collect: () => void,
type CollectOptions = {|
collection: Collection,
includeCritical: boolean,
|}

type Collected = {|
draggables: DraggableDimension[],
droppables: DroppableDimension[],
export type Collector = {|
stop: () => void,
collect: (options: CollectOptions) => void,
|}

type InternalOptions = {|
includeCritical: boolean,
type PublishArgs = {|
draggables: DraggableDimensionMap,
droppables: DroppableDimensionMap,
viewport: Viewport,
|}

type Args = {|
getEntries: () => Entries,
publish: (
droppables: DroppableDimension[],
draggables: DraggableDimension[],
viewport: Viewport,
) => void,
publish: (args: PublishArgs) => void,
|}

const defaultOptions: InternalOptions = {
includeCritical: true,
};

export default ({
publish,
getEntries,
}: Args): Collector => {
let frameId: ?AnimationFrameID = null;
let isActive: boolean = false;
let collection: ?Collection;
let isQueued: boolean = false;
let isRunning: boolean = false;

const collectFromDOM = (windowScroll: Position, options: InternalOptions): Collected => {
invariant(isActive, 'Should not collect when not active');
invariant(collection, 'Need collection options to pull from DOM');

const collectFromDOM = (windowScroll: Position, options: CollectOptions): Collected => {
const { collection, includeCritical } = options;
const entries: Entries = getEntries();
const home: DroppableDescriptor = collection.critical.droppable;
const dragging: DraggableDescriptor = collection.critical.draggable;
Expand All @@ -75,7 +65,7 @@ export default ({
.filter((entry: DroppableEntry): boolean => entry.descriptor.type === home.type)
// Exclude the critical droppable if needed
.filter((entry: DroppableEntry): boolean => {
if (options.includeCritical) {
if (includeCritical) {
return true;
}

Expand All @@ -102,7 +92,7 @@ export default ({
})
.filter((entry: DraggableEntry): boolean => {
// Exclude the critical draggable if needed
if (options.includeCritical) {
if (includeCritical) {
return true;
}
return entry.descriptor.id !== dragging.id;
Expand Down Expand Up @@ -131,77 +121,45 @@ export default ({
};
};

const run = (options?: InternalOptions = defaultOptions) => {
invariant(!isRunning, 'Cannot start a new run when a run is already occurring');
const abortFrame = () => {
if (!frameId) {
return;
}
cancelAnimationFrame(frameId);
frameId = null;
};

isRunning = true;
const collect = (options: CollectOptions) => {
abortFrame();

// Perform DOM collection in next frame
frameId = requestAnimationFrame(() => {
timings.start('DOM collection');
const viewport: Viewport = getViewport();
const collected: Collected = collectFromDOM(viewport.scroll, options);
const collected: DimensionMap = collectFromDOM(viewport.scroll, options);
timings.finish('DOM collection');

// Perform publish in next frame
frameId = requestAnimationFrame(() => {
timings.start('Bulk dimension publish');
publish(collected.droppables, collected.draggables, viewport);
publish({
draggables: collected.draggables,
droppables: collected.droppables,
viewport,
});
timings.finish('Bulk dimension publish');

// TODO: what if publish caused collection?

frameId = null;
isRunning = false;

if (isQueued) {
isQueued = false;
run();
}
});
});
};

const start = (options: Collection) => {
invariant(!isActive, 'Collector has already been started');
isActive = true;
collection = options;

// Start a collection - but there is no need to collect the
// critical dimensions as they have already been collected
run({ includeCritical: false });
};

const collect = () => {
invariant(isActive, 'Can only collect when active');
// A run is already queued
if (isQueued) {
return;
}

// We are running and a collection is not queued
// Queue another run
if (isRunning) {
isQueued = true;
return;
}

run();
};

const stop = () => {
if (frameId) {
cancelAnimationFrame(frameId);
}
isRunning = false;
isQueued = false;
isActive = false;
collection = null;
abortFrame();
};

return {
start,
stop,
collect,
stop,
};
};
39 changes: 24 additions & 15 deletions src/state/dimension-marshal/dimension-marshal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,14 @@ import { type Position } from 'css-box-model';
import invariant from 'tiny-invariant';
import createCollector, { type Collector } from './collector';
// TODO: state folder reaching into view
import getViewport from '../../view/window/get-viewport';
import * as timings from '../../debug/timings';
import type {
DraggableId,
DroppableId,
DroppableDescriptor,
DraggableDescriptor,
DraggableDimension,
DroppableDimension,
DimensionMap,
State as AppState,
LiftRequest,
Viewport,
} from '../../types';
import type {
DimensionMarshal,
Expand All @@ -25,8 +20,6 @@ import type {
Entries,
DroppableEntry,
DraggableEntry,
DroppableEntryMap,
DraggableEntryMap,
Collection,
} from './dimension-marshal-types';

Expand All @@ -42,6 +35,14 @@ export default (callbacks: Callbacks) => {
getEntries: () => entries,
});

const collect = ({ includeCritical }: {| includeCritical: boolean |}) => {
invariant(collection, 'Cannot collect without a collection occurring');
collector.collect({
collection,
includeCritical,
});
};

const registerDraggable = (
descriptor: DraggableDescriptor,
getDimension: GetDraggableDimensionFn
Expand Down Expand Up @@ -77,7 +78,9 @@ export default (callbacks: Callbacks) => {
return;
}

collector.collect();
invariant(descriptor.id !== collection.critical.draggable.id, 'Cannot unregister dragging item during a drag');

collect({ includeCritical: false });
};

const updateDraggable = (
Expand All @@ -99,6 +102,8 @@ export default (callbacks: Callbacks) => {

const home: ?DroppableEntry = entries.droppables[descriptor.droppableId];
invariant(home, 'Cannot update a Draggable that does not have a home');

collect({ includeCritical: false });
};

const unregisterDraggable = (descriptor: DraggableDescriptor) => {
Expand All @@ -118,7 +123,9 @@ export default (callbacks: Callbacks) => {
return;
}

console.warn('TODO: batch unpublish draggable');
invariant(descriptor.id !== collection.critical.draggable.id, 'Cannot unregister dragging item during a drag');

collect({ includeCritical: false });
};

const registerDroppable = (
Expand Down Expand Up @@ -147,7 +154,9 @@ export default (callbacks: Callbacks) => {
return;
}

collector.collect();
invariant(descriptor.id !== collection.critical.droppable.id, 'Cannot register home droppable during a drag');

collect({ includeCritical: false });
};

const updateDroppable = (
Expand All @@ -165,6 +174,8 @@ export default (callbacks: Callbacks) => {
delete entries.droppables[previous.id];

registerDroppable(descriptor, droppableCallbacks);

collect({ includeCritical: false });
};

const unregisterDroppable = (descriptor: DroppableDescriptor) => {
Expand All @@ -188,7 +199,9 @@ export default (callbacks: Callbacks) => {
return;
}

console.warn('TODO: publish droppable unpublish');
invariant(descriptor.id !== collection.critical.droppable.id, 'Cannot unregister home droppable during a drag');

collect({ includeCritical: false });
};

const updateDroppableIsEnabled = (id: DroppableId, isEnabled: boolean) => {
Expand Down Expand Up @@ -280,10 +293,6 @@ export default (callbacks: Callbacks) => {
return getCritical(windowScroll);
};

const collect = ({ includeCritical }: CollectionOptions) => {
invariant(collection, 'Cannot collect without a collection occurring');
};

const marshal: DimensionMarshal = {

registerDraggable,
Expand Down
52 changes: 23 additions & 29 deletions src/state/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ const updateStateAfterDimensionChange = (newState: State, impact?: ?DragImpact):
});
};

export default (state: State = clean('IDLE'), action: Action): State => {
export default (state: State = clean(), action: Action): State => {
if (action.type === 'CLEAN') {
return clean();
}
Expand All @@ -240,30 +240,17 @@ export default (state: State = clean('IDLE'), action: Action): State => {
return result;
}

if (action.type === 'REQUEST_DIMENSIONS') {
if (state.phase !== 'PREPARING') {
console.error('Trying to start a lift while not preparing for a lift');
return clean();
}

const request: LiftRequest = action.payload;

const result: InitialCollectionState = {
phase: 'INITIAL_COLLECTION',
request,
};
return result;
}

if (action.type === 'INITIAL_PUBLISH') {
invariant(state.phase === 'INITIAL_COLLECTION', 'INITITIAL_PUBLISH must come after a INITIAL_COLLECTION');
const existing: InitialCollectionState = state;
const { draggable, home, viewport, autoScrollMode } = action.payload;
invariant(state.phase === 'PREPARING', 'INITIAL_PUBLISH must come after a PREPARING phase');
const current: PreparingState = state;
const { critical, client, autoScrollMode, viewport } = action.payload;

const result: BulkCollectionState = {
// We are now waiting for the first bulk collection
phase: 'BULK_COLLECTION',
critical: {
draggable: draggable.descriptor,
// TODO: populate correctly
draggable: critical.draggable,
droppable: home.descriptor,
},
autoScrollMode,
Expand Down Expand Up @@ -522,9 +509,21 @@ export default (state: State = clean('IDLE'), action: Action): State => {
return state;
}

// Should not occur
if (state.phase !== 'DRAGGING' || state.phase !== 'BULK_COLLECTING') {
return state;
}

// Otherwise get an incorrect index calculated before the other dimensions are published
const { client, viewport, shouldAnimate } = action.payload;
const drag: ?DragState = state.drag;

if (state.phase === 'BULK_COLLECTING') {
// can update position but not impact
}

if (state.phase === 'DRAGGING') {
// can update position and impact (unless it is jump scrolling)
}

if (!drag) {
console.error('Cannot move while there is no drag state');
Expand Down Expand Up @@ -721,16 +720,11 @@ export default (state: State = clean('IDLE'), action: Action): State => {

if (action.type === 'DROP_COMPLETE') {
const result: DropResult = action.payload;

return {
const newState: DropCompleteState = {
phase: 'DROP_COMPLETE',
drag: null,
drop: {
pending: null,
result,
},
dimension: noDimensions,
result,
};
return newState;
}

return state;
Expand Down
Loading

0 comments on commit ed8a743

Please sign in to comment.