@dou-ui/gantt 0.0.0-stage → 0.1.0-alpha.0
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 +21 -0
- package/README.md +10 -2
- package/dist/collaboration/index.js +323 -0
- package/dist/collaboration/index.js.map +1 -0
- package/dist/collaboration/peers.js +78 -0
- package/dist/collaboration/peers.js.map +1 -0
- package/dist/components/cell-editor.js +6 -0
- package/dist/components/cell-editor.js.map +1 -0
- package/dist/components/cell-editor.vue_vue_type_script_setup_true_lang.js +114 -0
- package/dist/components/cell-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/gantt-menu.js +6 -0
- package/dist/components/gantt-menu.js.map +1 -0
- package/dist/components/gantt-menu.vue_vue_type_script_setup_true_lang.js +40 -0
- package/dist/components/gantt-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/time-grid.js +6 -0
- package/dist/components/time-grid.js.map +1 -0
- package/dist/components/time-grid.vue_vue_type_script_setup_true_lang.js +32 -0
- package/dist/components/time-grid.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/time-header.js +6 -0
- package/dist/components/time-header.js.map +1 -0
- package/dist/components/time-header.vue_vue_type_script_setup_true_lang.js +60 -0
- package/dist/components/time-header.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/context.js +12 -0
- package/dist/context.js.map +1 -0
- package/dist/core/baseline.js +48 -0
- package/dist/core/baseline.js.map +1 -0
- package/dist/core/calendar.js +191 -0
- package/dist/core/calendar.js.map +1 -0
- package/dist/core/csv.js +424 -0
- package/dist/core/csv.js.map +1 -0
- package/dist/core/document.js +231 -0
- package/dist/core/document.js.map +1 -0
- package/dist/core/extension.js +42 -0
- package/dist/core/extension.js.map +1 -0
- package/dist/core/geometry.js +112 -0
- package/dist/core/geometry.js.map +1 -0
- package/dist/core/history.js +70 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/links.js +72 -0
- package/dist/core/links.js.map +1 -0
- package/dist/core/model.js +52 -0
- package/dist/core/model.js.map +1 -0
- package/dist/core/order.js +34 -0
- package/dist/core/order.js.map +1 -0
- package/dist/core/scale.js +118 -0
- package/dist/core/scale.js.map +1 -0
- package/dist/core/schedule.js +235 -0
- package/dist/core/schedule.js.map +1 -0
- package/dist/core/time.js +81 -0
- package/dist/core/time.js.map +1 -0
- package/dist/core/transaction.js +371 -0
- package/dist/core/transaction.js.map +1 -0
- package/dist/core/tree.js +114 -0
- package/dist/core/tree.js.map +1 -0
- package/dist/export/draw.js +214 -0
- package/dist/export/draw.js.map +1 -0
- package/dist/export/theme.js +131 -0
- package/dist/export/theme.js.map +1 -0
- package/dist/gantt.js +6 -0
- package/dist/gantt.js.map +1 -0
- package/dist/gantt.vue_vue_type_script_setup_true_lang.js +2774 -0
- package/dist/gantt.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/labels.js +87 -0
- package/dist/labels.js.map +1 -0
- package/dist/locale.js +355 -0
- package/dist/locale.js.map +1 -0
- package/dist/scheduler/index.js +8 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/layout.js +97 -0
- package/dist/scheduler/layout.js.map +1 -0
- package/dist/scheduler/scheduler.js +6 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/scheduler.vue_vue_type_script_setup_true_lang.js +1359 -0
- package/dist/scheduler/scheduler.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/scheduler/style.d.ts +1 -0
- package/dist/scheduler/style.js +2 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +4 -0
- package/dist/time-axis.js +337 -0
- package/dist/time-axis.js.map +1 -0
- package/dist/types/collaboration/index.d.ts +39 -0
- package/dist/types/collaboration/peers.d.ts +22 -0
- package/dist/types/components/cell-editor.vue.d.ts +21 -0
- package/dist/types/components/gantt-menu.vue.d.ts +18 -0
- package/dist/types/components/time-grid.vue.d.ts +12 -0
- package/dist/types/components/time-header.vue.d.ts +23 -0
- package/dist/types/context.d.ts +64 -0
- package/dist/types/core/baseline.d.ts +14 -0
- package/dist/types/core/calendar.d.ts +75 -0
- package/dist/types/core/csv.d.ts +77 -0
- package/dist/types/core/document.d.ts +51 -0
- package/dist/types/core/extension.d.ts +88 -0
- package/dist/types/core/geometry.d.ts +33 -0
- package/dist/types/core/history.d.ts +19 -0
- package/dist/types/core/links.d.ts +20 -0
- package/dist/types/core/menu.d.ts +27 -0
- package/dist/types/core/model.d.ts +72 -0
- package/dist/types/core/order.d.ts +9 -0
- package/dist/types/core/scale.d.ts +33 -0
- package/dist/types/core/schedule.d.ts +44 -0
- package/dist/types/core/time.d.ts +39 -0
- package/dist/types/core/transaction.d.ts +134 -0
- package/dist/types/core/tree.d.ts +30 -0
- package/dist/types/export/draw.d.ts +76 -0
- package/dist/types/export/theme.d.ts +49 -0
- package/dist/types/gantt.vue.d.ts +54 -0
- package/dist/types/index.d.ts +148 -0
- package/dist/types/labels.d.ts +24 -0
- package/dist/types/locale.d.ts +161 -0
- package/dist/types/scheduler/index.d.ts +102 -0
- package/dist/types/scheduler/layout.d.ts +58 -0
- package/dist/types/scheduler/scheduler.vue.d.ts +46 -0
- package/dist/types/scheduler/types.d.ts +109 -0
- package/dist/types/time-axis.d.ts +80 -0
- package/dist/types/types.d.ts +305 -0
- package/package.json +79 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_normalizeClass","_normalizeStyle","_unref","_createElementVNode","_toDisplayString","_Fragment","_renderList","_createBlock","_resolveDynamicComponent","_createCommentVNode","_renderSlot","_createTextVNode","_createVNode","TimeHeader","_withCtx","TimeGrid","GanttMenu"],"sources":["../../src/scheduler/scheduler.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ChevronDownIcon, ChevronRightIcon, TrashIcon } from '@dou-ui/icons'\nimport {\n holdPointer,\n matchesHotkey,\n useElementSize,\n useLocale,\n type ContextMenuItem,\n type PointerHold,\n} from 'dou-ui'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n toRaw,\n useId,\n useTemplateRef,\n watch,\n} from 'vue'\nimport GanttMenu from '../components/gantt-menu.vue'\nimport TimeGrid from '../components/time-grid.vue'\nimport TimeHeader from '../components/time-header.vue'\nimport { resolveCalendar } from '../core/calendar'\nimport { GanttHistory } from '../core/history'\nimport { readDocument } from '../core/document'\nimport { spanOf, writeSpan, type GanttTask, type TaskSpan } from '../core/model'\nimport { snapStep, type GanttScale } from '../core/scale'\nimport { MINUTES_PER_DAY, parseTime } from '../core/time'\nimport {\n emptyDocument,\n GanttTransaction,\n type GanttDocument,\n type GanttTransactionMeta,\n} from '../core/transaction'\nimport {\n dateLabel,\n datesLabel,\n durationLabel,\n endLabel,\n markerRoom,\n spokenDuration,\n} from '../labels'\nimport { format, useGanttMessages } from '../locale'\nimport { useTimeAxis } from '../time-axis'\nimport {\n groupByResource,\n loadSegments,\n type SchedulerResource,\n type SchedulerLoadSegment,\n type SchedulerItem,\n} from './layout'\nimport type {\n SchedulerEmits,\n SchedulerExpose,\n SchedulerMenuTarget,\n SchedulerMove,\n SchedulerProps,\n SchedulerRange,\n SchedulerSlots,\n} from './types'\n\ndefineOptions({ name: 'DouScheduler' })\n\nconst props = withDefaults(defineProps<SchedulerProps>(), {\n today: true,\n table: true,\n tableWidth: 200,\n rowHeight: 36,\n load: true,\n menu: true,\n})\nconst model = defineModel<GanttDocument>({ default: emptyDocument })\n/** The `v-model`, with a wrongly shaped one read as well as it can be. */\nconst source = computed(() => readDocument(model.value, false))\nconst tasks = computed(() => source.value.tasks)\nconst selection = defineModel<string[]>('selection', { default: () => [] })\nconst scale = defineModel<GanttScale>('scale')\nconst emit = defineEmits<SchedulerEmits>()\ndefineSlots<SchedulerSlots>()\n\nconst messages = useGanttMessages(() => props.messages)\nconst sm = computed(() => messages.value.scheduler)\nconst { locale } = useLocale()\nconst weekStart = computed(() => props.weekStart ?? locale.value.region.weekStart)\nconst calendar = computed(() => resolveCalendar(props.calendar))\nconst editable = computed(() => !props.readonly)\n\n/** Height of the two-row time header, in px. */\nconst HEADER = 56\n/** The distance from one lane to the next, in px. */\nconst LANE = 28\n/** Without the list, room above a resource's lanes for its name, in px. */\nconst CAPTION = 18\nconst OVERSCAN = 240\n/** Below this width the list steps aside and the timeline takes the whole width. */\nconst NARROW = 520\nconst TABLE_MIN = 120\n\nconst root = useTemplateRef<HTMLElement>('root')\nconst chart = useTemplateRef<HTMLElement>('chart')\nconst tableBody = useTemplateRef<HTMLElement>('tableBody')\nconst { width: rootWidth } = useElementSize(root)\nconst { width: viewWidth, height: viewHeight } = useElementSize(chart)\n\nconst narrow = computed(() => rootWidth.value > 0 && rootWidth.value < NARROW)\nconst showTable = computed(() => props.table && !narrow.value)\nconst caption = computed(() => (showTable.value ? 0 : CAPTION))\nconst tableSize = ref(props.tableWidth)\nwatch(\n () => props.tableWidth,\n (width) => (tableSize.value = width),\n)\n\n// Document and history -------------------------------------------------------------\n\nconst history = new GanttHistory()\nconst canUndo = ref(false)\nconst canRedo = ref(false)\n\n/*\n * A bound v-model only catches up when the parent renders, so changes made\n * in the same tick build on the latest commit instead.\n */\nlet latest: GanttDocument | null = null\nconst docOf = (): GanttDocument => latest ?? toRaw(source.value)\n\nfunction commit(tr: GanttTransaction) {\n if (!latest) void nextTick(() => (latest = null))\n latest = tr.doc\n model.value = tr.doc\n const ids = new Set(tr.doc.tasks.map((task) => task.id))\n const kept = selection.value.filter((id) => ids.has(id))\n if (kept.length !== selection.value.length) selection.value = kept\n emit('transaction', tr)\n}\n\n/** Applies changes as one transaction, one undo step. */\nfunction transact(fn: (tr: GanttTransaction) => void, meta?: GanttTransactionMeta) {\n const tr = new GanttTransaction(docOf())\n if (meta) tr.setMeta(meta)\n fn(tr)\n if (!tr.changed) return tr\n const before = selection.value\n commit(tr)\n history.record(tr, before, selection.value)\n canUndo.value = history.canUndo\n canRedo.value = history.canRedo\n // tasks added from outside, such as a booking for a drawn range, are read out\n const added = tr.steps.flatMap((step) => (step.type === 'addTask' ? [step.task.title] : []))\n if (added.length)\n announce(format(messages.value.taskAdded, { title: added.join(messages.value.listSeparator) }))\n return tr\n}\n\nfunction travel(direction: 'undo' | 'redo') {\n const result = history[direction](docOf())\n if (!result) return null\n result.tr.setMeta({ origin: direction, history: false })\n commit(result.tr)\n selection.value = result.selection\n canUndo.value = history.canUndo\n canRedo.value = history.canRedo\n return result.tr\n}\n\nconst undo = () => !!travel('undo')\nconst redo = () => !!travel('redo')\n\n/** Undoes or redoes, and reads out the task it changed. */\nfunction announceTravel(direction: 'undo' | 'redo') {\n const tr = travel(direction)\n if (!tr) return\n const m = messages.value\n // the change as first made: undoing runs the steps backwards\n const step = tr.steps[direction === 'undo' ? tr.steps.length - 1 : 0]!\n const id = step.type === 'addTask' ? step.task.id : 'id' in step ? step.id : ''\n void nextTick(() => {\n const found = itemById.value.get(id)\n const change = found\n ? describe(found.item, found.row)\n : format(m.taskRemoved, {\n title: tr.before.tasks.find((task) => task.id === id)?.title ?? '',\n })\n announce(format(m[direction === 'undo' ? 'undone' : 'redone'], { change }))\n })\n}\n\n// Rows -------------------------------------------------------------------------------\n\ninterface GroupRow {\n kind: 'group'\n key: string\n title: string\n top: number\n height: number\n}\n\ninterface ResourceRow {\n kind: 'resource'\n key: string\n /** `null` for the row of tasks without a resource. */\n resource: SchedulerResource | null\n title: string\n items: SchedulerItem[]\n lanes: number\n load: SchedulerLoadSegment[]\n capacity: number\n overloaded: boolean\n top: number\n height: number\n}\n\ntype Row = GroupRow | ResourceRow\n\nconst collapsed = ref(new Set<string>())\nconst drag = shallowRef<Drag | null>(null)\nconst taskList = computed(() => toRaw(tasks.value))\n/** The tasks as shown: while dragging, as they would be after the drop. */\nconst shown = computed(() => {\n // only once a drag has begun, which is after everything here is set up\n if (!drag.value?.started) return taskList.value\n const plans = planned.value\n if (!plans?.length) return taskList.value\n const patches = new Map(plans.map((plan) => [plan.id, plan.patch]))\n return taskList.value.map((task) => {\n const patch = patches.get(task.id)\n return patch ? { ...task, ...patch } : task\n })\n})\nconst placed = computed(() => groupByResource(shown.value, props.resources))\n/**\n * While dragging, rows keep the lanes they had: a row that shrank would\n * pull the rows below up under the pointer.\n */\nconst keptLanes = shallowRef<Map<string, number> | null>(null)\n\nconst rows = computed<Row[]>(() => {\n const out: Row[] = []\n let top = 0\n const push = (row: Omit<GroupRow, 'top'> | Omit<ResourceRow, 'top'>) => {\n out.push({ ...row, top } as Row)\n top += row.height\n }\n const resourceRow = (resource: SchedulerResource | null): Omit<ResourceRow, 'top'> => {\n const entry = placed.value.get(resource?.id ?? '')\n const lanes = Math.max(entry?.lanes ?? 0, keptLanes.value?.get(resource?.id ?? '') ?? 0)\n const load = loadSegments((entry?.items ?? []).map((item) => item.span))\n const capacity = Math.max(1, resource?.capacity ?? 1)\n return {\n kind: 'resource',\n key: resource?.id ?? '',\n resource,\n title: resource?.title ?? sm.value.unassigned,\n items: entry?.items ?? [],\n lanes,\n load,\n capacity,\n overloaded: !!resource && load.some((segment) => segment.count > capacity),\n height: props.rowHeight + Math.max(0, lanes - 1) * LANE + caption.value,\n }\n }\n const done = new Set<string>()\n for (const resource of props.resources) {\n if (!resource.group) {\n push(resourceRow(resource))\n continue\n }\n if (done.has(resource.group)) continue\n done.add(resource.group)\n const key = `group:${resource.group}`\n push({ kind: 'group', key, title: resource.group, height: props.rowHeight })\n if (collapsed.value.has(key)) continue\n for (const member of props.resources)\n if (member.group === resource.group) push(resourceRow(member))\n }\n if (placed.value.has('')) push(resourceRow(null))\n return out\n})\n\nconst rowByKey = computed(() => new Map(rows.value.map((row) => [row.key, row])))\nconst totalHeight = computed(() => {\n const last = rows.value.at(-1)\n return last ? last.top + last.height : 0\n})\n/** Where each task is drawn. */\nconst itemById = computed(() => {\n const out = new Map<string, { item: SchedulerItem; row: ResourceRow }>()\n for (const row of rows.value)\n if (row.kind === 'resource') for (const item of row.items) out.set(item.task.id, { item, row })\n return out\n})\n\nfunction toggle(row: GroupRow) {\n const next = new Set(collapsed.value)\n if (next.has(row.key)) next.delete(row.key)\n else next.add(row.key)\n collapsed.value = next\n}\n\n// Time axis ----------------------------------------------------------------------------\n\nconst content = computed(() => {\n let start = Infinity\n let end = -Infinity\n for (const entry of placed.value.values())\n for (const { span } of entry.items) {\n start = Math.min(start, span.start)\n end = Math.max(end, span.end)\n }\n return start > end ? null : { start, end }\n})\n\nconst axis = useTimeAxis({\n chart,\n tableBody,\n viewWidth,\n scale,\n range: () => props.range,\n today: () => props.today,\n weekStart,\n calendar,\n messages,\n content,\n fitWidth: () => (showTable.value ? viewWidth.value : rootWidth.value),\n})\nconst {\n level,\n ppm,\n now,\n extent,\n origin,\n totalWidth,\n xOf,\n contentX,\n scrollTop,\n scrollLeft,\n scrollbar,\n topCells,\n bottomCells,\n shaded,\n todayX,\n timeWindow,\n} = axis\n\nwatch([viewHeight, viewWidth], axis.measureScrollbar, { flush: 'post' })\nwatch([rootWidth, viewWidth], axis.fitWhenSized)\n\nconst markers = computed(() => {\n const inRange = (props.markers ?? []).flatMap((marker, index) => {\n const at = parseTime(marker.date)?.at\n if (at == null || at < extent.value.start || at > extent.value.end) return []\n return [{ key: `${index}:${marker.date}`, x: xOf(at), marker }]\n })\n const room = markerRoom(inRange.map((item) => (item.marker.label ? item.x : -Infinity)))\n return inRange.map((item, i) => ({ ...item, room: room[i]! }))\n})\n\n// What is in view ---------------------------------------------------------------------\n\nconst bodyHeight = computed(() => Math.max(0, viewHeight.value - HEADER))\n\n/** The rows in view, with some room above and below. */\nconst visibleRows = computed(() => {\n const list = rows.value\n const from = scrollTop.value - OVERSCAN\n const to = scrollTop.value + bodyHeight.value + OVERSCAN\n // the first row that ends below `from`\n let lo = 0\n let hi = list.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (list[mid]!.top + list[mid]!.height <= from) lo = mid + 1\n else hi = mid\n }\n const out: Row[] = []\n for (let i = lo; i < list.length && list[i]!.top < to; i++) out.push(list[i]!)\n return out\n})\n\nconst resourceRows = computed(() =>\n visibleRows.value.filter((row): row is ResourceRow => row.kind === 'resource'),\n)\n\n/** Where a lane's bar row sits, in body px. */\nconst laneTop = (row: ResourceRow, lane: number) => row.top + caption.value + lane * LANE\n\nconst describeRow = (row: ResourceRow) => {\n const text = format(sm.value.row, { title: row.title, count: row.items.length })\n return row.overloaded ? format(sm.value.overloaded, { row: text }) : text\n}\n\nfunction describe(item: SchedulerItem, row: ResourceRow) {\n const m = messages.value\n const { task, span } = item\n // as the gantt chart reads them out\n const text =\n task.type === 'milestone' || span.end <= span.start\n ? format(m.milestone, {\n title: task.title,\n start: dateLabel(\n span.start - (span.dateOnly ? MINUTES_PER_DAY / 2 : 0),\n span.dateOnly,\n m,\n ),\n })\n : format(sm.value.task, {\n title: task.title,\n dates: datesLabel(span, m),\n duration: spokenDuration(span, calendar.value, m),\n })\n return format(sm.value.item, { task: text, resource: row.title })\n}\n\nconst selected = computed(() => new Set(selection.value))\n\nlet canvas: CanvasRenderingContext2D | null | undefined\n/** Width of a bar title in px; estimated where text can't be measured. */\nfunction textWidth(text: string) {\n // measure only once the chart is in the page and its font is known\n if (canvas === undefined && root.value) {\n try {\n canvas = document.createElement('canvas').getContext('2d')\n if (canvas) {\n const style = getComputedStyle(root.value)\n canvas.font = `${style.getPropertyValue('--dou-font-size-sm').trim() || '13px'} ${style.fontFamily}`\n }\n } catch {\n canvas = null\n }\n }\n return canvas ? canvas.measureText(text).width : text.length * 13\n}\n\ninterface Bar {\n item: SchedulerItem\n row: ResourceRow\n left: number\n width: number\n top: number\n milestone: boolean\n /** The title doesn't fit in the bar: it goes after it. */\n outside: boolean\n aria: string\n}\n\nconst bars = computed<Bar[]>(() => {\n const { start, end } = timeWindow.value\n const out: Bar[] = []\n for (const row of resourceRows.value)\n for (const item of row.items) {\n const { span } = item\n if (span.end < start || span.start > end) continue\n const milestone = item.task.type === 'milestone'\n const width = Math.max(milestone ? 0 : 2, (span.end - span.start) * ppm.value)\n out.push({\n item,\n row,\n left: xOf(span.start),\n width,\n top: laneTop(row, item.lane),\n milestone,\n outside: milestone || textWidth(item.task.title) + 20 > width,\n aria: describe(item, row),\n })\n }\n return out\n})\n\n/** How busy each row in view is, as stretches under it. */\nconst loads = computed(() => {\n if (!props.load) return []\n const { start, end } = timeWindow.value\n return resourceRows.value.flatMap((row) =>\n row.resource\n ? row.load\n .filter((segment) => segment.end > start && segment.start < end)\n .map((segment) => ({\n key: `${row.key}:${segment.start}`,\n top: row.top + row.height - 6,\n left: xOf(segment.start),\n width: Math.max(1, (segment.end - segment.start) * ppm.value),\n level: Math.min(1, segment.count / row.capacity),\n over: segment.count > row.capacity,\n }))\n : [],\n )\n})\n\n/** Without the list, rows show their title at the left edge of the timeline. */\nconst rowTitles = computed(() => (showTable.value ? [] : visibleRows.value))\n\n// Table ----------------------------------------------------------------------------------\n\nconst tableMax = computed(() => Math.max(TABLE_MIN, Math.round((rootWidth.value || 1000) * 0.5)))\nconst hovered = ref<string | null>(null)\n\nfunction onDividerDown(event: PointerEvent) {\n if (event.button !== 0) return\n event.preventDefault()\n const x0 = event.clientX\n const width0 = tableSize.value\n const move = (e: PointerEvent) =>\n (tableSize.value = Math.min(tableMax.value, Math.max(TABLE_MIN, width0 + e.clientX - x0)))\n const up = () => {\n window.removeEventListener('pointermove', move)\n window.removeEventListener('pointerup', up)\n window.removeEventListener('pointercancel', up)\n }\n window.addEventListener('pointermove', move)\n window.addEventListener('pointerup', up)\n window.addEventListener('pointercancel', up)\n}\n\nfunction onDividerKey(event: KeyboardEvent) {\n const step = event.shiftKey ? 40 : 10\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return\n event.preventDefault()\n const next = tableSize.value + (event.key === 'ArrowLeft' ? -step : step)\n tableSize.value = Math.min(tableMax.value, Math.max(TABLE_MIN, next))\n}\n\n// Selection ------------------------------------------------------------------------------\n\nconst active = ref<string | null>(null)\n\nfunction select(task: GanttTask, event: MouseEvent | KeyboardEvent) {\n const id = task.id\n if (event.shiftKey || event.metaKey || event.ctrlKey)\n selection.value = selected.value.has(id)\n ? selection.value.filter((item) => item !== id)\n : [...selection.value, id]\n else if (selection.value.length !== 1 || selection.value[0] !== id) selection.value = [id]\n}\n\nfunction onTaskClick(task: GanttTask, event: MouseEvent) {\n if (dragged) return\n active.value = task.id\n select(task, event)\n emit('taskClick', task, event)\n}\n\n// Dragging ---------------------------------------------------------------------------------\n\ntype DragMode = 'move' | 'start' | 'end' | 'draw'\n\ninterface Drag {\n mode: DragMode\n /** The task pressed; empty when drawing. */\n id: string\n pointerId: number\n touch: boolean\n /** Where the press was and where the pointer is, in timeline px. */\n x0: number\n x: number\n y0: number\n y: number\n clientX: number\n clientY: number\n started: boolean\n /** The tasks that move, with their spans and rows when the drag began. */\n spans: Map<string, { span: TaskSpan; row: string; lane: number }>\n /** The row pressed, and the row under the pointer. */\n from: string\n to: string\n}\n\nconst THRESHOLD = { mouse: 3, touch: 6 }\nconst LONG_PRESS = 300\nconst EDGE = 32\n\nlet dragged = false\nlet pressTimer: ReturnType<typeof setTimeout> | undefined\nlet frame = 0\nlet hold: PointerHold | null = null\n\nconst snap = (at: number, step: number) => Math.round(at / step) * step\nconst edgeSpeed = (gap: number) => (gap < EDGE ? Math.ceil(((EDGE - gap) / EDGE) * 16) : 0)\n\n/** The step a drag snaps to: whole days when any task is date-only. */\nfunction stepFor(spans: Iterable<{ dateOnly: boolean }>) {\n const unit = snapStep(axis.dayWidth.value)\n for (const span of spans) if (span.dateOnly) return Math.max(unit, MINUTES_PER_DAY)\n return unit\n}\n\n/** The body y of a pointer. */\nconst contentY = (clientY: number) =>\n clientY - chart.value!.getBoundingClientRect().top - HEADER + chart.value!.scrollTop\n\n/** The resource row at a body y, if any. */\nfunction resourceRowAt(y: number): ResourceRow | null {\n const list = rows.value\n let lo = 0\n let hi = list.length - 1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n const row = list[mid]!\n if (y < row.top) hi = mid - 1\n else if (y >= row.top + row.height) lo = mid + 1\n else return row.kind === 'resource' ? row : null\n }\n return null\n}\n\nconst taskById = (id: string) => docOf().tasks.find((task) => task.id === id)\n\ninterface Planned {\n id: string\n span: TaskSpan\n /** The row it goes to. */\n row: string\n patch: Partial<GanttTask>\n}\n\n/** What the current drag would do. */\nconst planned = computed<Planned[] | null>(() => {\n const d = drag.value\n if (!d?.started || d.mode === 'draw') return null\n const delta = (d.x - d.x0) / ppm.value\n const out: Planned[] = []\n const first = d.spans.get(d.id)!\n const unit = stepFor([...d.spans.values()].map((entry) => entry.span))\n for (const [id, entry] of d.spans) {\n const task = taskById(id)\n if (!task) continue\n const { span } = entry\n let start = span.start\n let end = span.end\n if (d.mode === 'move') {\n const shift = snap(first.span.start + delta, unit) - first.span.start\n start += shift\n end += shift\n } else if (d.mode === 'start') start = Math.min(snap(span.start + delta, unit), span.end - unit)\n else end = Math.max(snap(span.end + delta, unit), span.start + unit)\n // tasks from the pressed row follow the pointer to another row\n const row = d.mode === 'move' && entry.row === d.from ? d.to : entry.row\n const patch: Partial<GanttTask> = writeSpan(task, start, end)\n if (row !== entry.row) patch.resource = row || undefined\n out.push({ id, span: { start, end, dateOnly: span.dateOnly }, row, patch })\n }\n return out\n})\n\n/**\n * Why `canMove` refuses changes, or `null` when it allows them all. Each\n * patch is checked with the resource it ends up with.\n */\nfunction checkMove(patches: Iterable<{ id: string; patch: Partial<GanttTask> }>) {\n const rule = props.canMove\n if (!rule) return null\n const doc = docOf()\n for (const { id, patch } of patches) {\n const task = taskById(id)\n if (!task) continue\n const next = { ...task, ...patch }\n if (!next.start) continue\n const known = next.resource && props.resources.some((item) => item.id === next.resource)\n const move: SchedulerMove = {\n task,\n start: next.start,\n end: next.end,\n resource: known ? next.resource : undefined,\n }\n const answer = rule(move, doc)\n if (answer === true) continue\n return typeof answer === 'string' && answer ? answer : messages.value.moveRefused\n }\n return null\n}\n\n/** Why the current drag would be refused. */\nconst dragRefusal = computed(() => {\n const plans = planned.value\n return plans?.length ? checkMove(plans) : null\n})\n\n/** The range being drawn on an empty part of a row. */\nconst drawn = computed(() => {\n const d = drag.value\n if (!d?.started || d.mode !== 'draw') return null\n const unit = snapStep(axis.dayWidth.value)\n const a = origin.value + Math.min(d.x0, d.x) / ppm.value\n const b = origin.value + Math.max(d.x0, d.x) / ppm.value\n const start = Math.floor(a / unit) * unit\n const end = Math.max(start + unit, Math.ceil(b / unit) * unit)\n return { row: d.from, start, end, dateOnly: unit >= MINUTES_PER_DAY }\n})\n\n/** A dashed outline over the range being drawn. */\nconst drawnBox = computed(() => {\n const range = drawn.value\n const row = range && rowByKey.value.get(range.row)\n if (!range || row?.kind !== 'resource') return null\n return {\n left: xOf(range.start),\n width: (range.end - range.start) * ppm.value,\n top: laneTop(row, 0),\n }\n})\n\n/** The new dates beside the pointer while dragging. */\nconst dragTip = computed(() => {\n const d = drag.value\n if (!d?.started) return null\n const m = messages.value\n const found = d.mode === 'draw' ? undefined : itemById.value.get(d.id)\n const span = found?.item.span ?? (drawn.value && { ...drawn.value })\n const row = found?.row ?? rowByKey.value.get(d.from)\n if (!span || row?.kind !== 'resource') return null\n const refusal = d.mode === 'draw' ? null : dragRefusal.value\n const text = refusal\n ? refusal\n : span.end > span.start\n ? format(m.rangeTip, {\n start: dateLabel(span.start, span.dateOnly, m),\n end: endLabel(span, m),\n duration: durationLabel(span, calendar.value, m),\n })\n : dateLabel(span.start - (span.dateOnly ? MINUTES_PER_DAY / 2 : 0), span.dateOnly, m)\n return {\n text,\n refused: !!refusal,\n left: Math.max(scrollLeft.value + 8, xOf(span.start)),\n top: laneTop(row, found?.item.lane ?? 0),\n }\n})\n\nfunction startDrag(event: PointerEvent, mode: DragMode, id: string, from: ResourceRow) {\n const touch = event.pointerType === 'touch'\n const spans = new Map<string, { span: TaskSpan; row: string; lane: number }>()\n if (mode !== 'draw') {\n const ids = mode === 'move' && selected.value.has(id) ? selection.value : [id]\n for (const each of ids) {\n const found = itemById.value.get(each)\n if (found && !found.item.task.locked)\n spans.set(each, { span: found.item.span, row: found.row.key, lane: found.item.lane })\n }\n if (!spans.has(id)) return\n }\n hold?.release()\n hold = holdPointer(event, root.value)\n const x = contentX(event.clientX)\n const y = contentY(event.clientY)\n const d: Drag = {\n mode,\n id,\n pointerId: event.pointerId,\n touch,\n x0: x,\n x,\n y0: y,\n y,\n clientX: event.clientX,\n clientY: event.clientY,\n started: false,\n spans,\n from: from.key,\n to: from.key,\n }\n drag.value = d\n window.addEventListener('pointermove', onDragMove)\n window.addEventListener('pointerup', onDragEnd)\n window.addEventListener('pointercancel', stopDrag)\n window.addEventListener('keydown', onDragKey, true)\n // a finger picks a bar up, or starts a range, after a short rest\n if (touch)\n pressTimer = setTimeout(() => {\n if (drag.value !== d) return\n begin(d)\n navigator.vibrate?.(8)\n }, LONG_PRESS)\n}\n\nfunction begin(d: Drag) {\n d.started = true\n keptLanes.value = new Map(\n rows.value.flatMap((row) => (row.kind === 'resource' ? [[row.key, row.lanes] as const] : [])),\n )\n hold?.grab()\n window.getSelection()?.removeAllRanges()\n frame = requestAnimationFrame(autoScroll)\n drag.value = { ...d }\n}\n\nfunction update(d: Drag, x: number, y: number) {\n const next = { ...d, x, y }\n if (d.mode === 'move') next.to = resourceRowAt(y)?.key ?? d.to\n drag.value = next\n}\n\nfunction onDragMove(event: PointerEvent) {\n const d = drag.value\n if (!d || event.pointerId !== d.pointerId) return\n d.clientX = event.clientX\n d.clientY = event.clientY\n const x = contentX(event.clientX)\n const y = contentY(event.clientY)\n if (!d.started) {\n const moved = Math.hypot(x - d.x0, y - d.y0)\n // a finger that moves before the long press scrolls instead\n if (d.touch) {\n if (moved > THRESHOLD.touch) stopDrag()\n return\n }\n if (moved < THRESHOLD.mouse) return\n begin(d)\n }\n update(drag.value!, x, y)\n}\n\nfunction autoScroll() {\n const d = drag.value\n const el = chart.value\n if (!d?.started || !el) return\n const rect = el.getBoundingClientRect()\n // only towards where the pointer has gone, so a bar picked up by the edge doesn't run off\n let dx = -edgeSpeed(d.clientX - rect.left) || edgeSpeed(rect.right - d.clientX)\n if (Math.sign(dx) !== Math.sign(d.x - d.x0)) dx = 0\n let dy = -edgeSpeed(d.clientY - rect.top - HEADER) || edgeSpeed(rect.bottom - d.clientY)\n if (d.mode !== 'move' || Math.sign(dy) !== Math.sign(d.y - d.y0)) dy = 0\n if (dx || dy) {\n el.scrollLeft += dx\n el.scrollTop += dy\n update(d, contentX(d.clientX), contentY(d.clientY))\n }\n frame = requestAnimationFrame(autoScroll)\n}\n\nfunction onDragEnd(event: PointerEvent) {\n const d = drag.value\n if (!d || event.pointerId !== d.pointerId) return\n // a finger held on a bar and let go without moving: the task's menu\n if (d.touch && d.started && d.mode === 'move' && Math.abs(d.x - d.x0) < THRESHOLD.touch) {\n const found = itemById.value.get(d.id)\n stopDrag()\n if (found && menuAllowed(found.item.task, event.clientX, event.clientY))\n showMenu(taskTarget(found.item.task, found.row), event.clientX, event.clientY)\n return\n }\n if (d.started) {\n dragged = true\n setTimeout(() => (dragged = false))\n if (d.mode === 'draw') finishDraw()\n else finishMove(d)\n } else if (d.mode === 'draw' && !d.touch) selection.value = []\n stopDrag()\n}\n\nfunction finishMove(d: Drag) {\n const plans = planned.value\n if (!plans?.length) return\n if (dragRefusal.value) return void announce(dragRefusal.value)\n transact((tr) => {\n for (const plan of plans) tr.updateTask(plan.id, plan.patch)\n })\n const pressed = plans.find((plan) => plan.id === d.id)\n const row = pressed && rowByKey.value.get(pressed.row)\n if (pressed && pressed.row !== d.from && row)\n announce(format(sm.value.moved, { title: taskById(d.id)?.title ?? '', resource: row.title }))\n}\n\nfunction finishDraw() {\n const range = drawn.value\n if (!range) return\n const span = writeSpan({ id: '', title: '' }, range.start, range.end)\n const out: SchedulerRange = {\n resource: range.row || undefined,\n start: span.start!,\n end: span.end ?? span.start!,\n }\n emit('create', out)\n}\n\nfunction onDragKey(event: KeyboardEvent) {\n if (event.key !== 'Escape') return\n event.preventDefault()\n event.stopPropagation()\n stopDrag()\n}\n\nfunction stopDrag() {\n clearTimeout(pressTimer)\n cancelAnimationFrame(frame)\n hold?.release()\n hold = null\n drag.value = null\n keptLanes.value = null\n window.removeEventListener('pointermove', onDragMove)\n window.removeEventListener('pointerup', onDragEnd)\n window.removeEventListener('pointercancel', stopDrag)\n window.removeEventListener('keydown', onDragKey, true)\n}\n\nfunction onBarDown(event: PointerEvent, bar: Bar) {\n if (event.button !== 0 || !editable.value) return\n event.stopPropagation()\n const handle = (event.currentTarget as HTMLElement).dataset.handle\n const mode: DragMode = handle === 'start' || handle === 'end' ? handle : 'move'\n if (bar.item.task.locked) return\n startDrag(event, mode, bar.item.task.id, bar.row)\n}\n\nfunction onBodyDown(event: PointerEvent) {\n if (event.button !== 0 || !editable.value) return\n const row = resourceRowAt(contentY(event.clientY))\n if (row) startDrag(event, 'draw', '', row)\n else if (event.pointerType !== 'touch') selection.value = []\n}\n\n// two fingers zoom; while they do, nothing is dragged\nconst onTouchMove = (event: TouchEvent) => void axis.pinchMove(event)\nconst onTouchEnd = (event: TouchEvent) => axis.pinchEnd(event)\nfunction onTouchStart(event: TouchEvent) {\n if (axis.pinchStart(event)) stopDrag()\n}\n\nonMounted(() => {\n const el = root.value!\n el.addEventListener('touchstart', onTouchStart, { passive: true })\n el.addEventListener('touchmove', onTouchMove, { passive: false })\n el.addEventListener('touchend', onTouchEnd)\n el.addEventListener('touchcancel', onTouchEnd)\n})\nonBeforeUnmount(() => {\n const el = root.value\n el?.removeEventListener('touchstart', onTouchStart)\n el?.removeEventListener('touchmove', onTouchMove)\n el?.removeEventListener('touchend', onTouchEnd)\n el?.removeEventListener('touchcancel', onTouchEnd)\n stopDrag()\n})\n\n// Menu -------------------------------------------------------------------------------------\n\nconst menu = useTemplateRef<InstanceType<typeof GanttMenu>>('menu')\nconst menuItems = shallowRef<ContextMenuItem[]>([])\nconst menuOpen = ref(false)\n\n/** The moment under a point on screen, or the task's start when it is off the timeline. */\nfunction timeAt(x: number, fallback: number) {\n const rect = chart.value!.getBoundingClientRect()\n if (x < rect.left || x > rect.right) return fallback\n return Math.round(origin.value + contentX(x) / ppm.value)\n}\n\nconst taskTarget = (task: GanttTask, row: ResourceRow) =>\n ({ kind: 'task', task, resource: row.resource, time: 0 }) as const\n\n/** Your items, then the built-in one, a separator between them. */\nfunction itemsFor(target: SchedulerMenuTarget) {\n const items: ContextMenuItem[] = [...(props.contextMenu?.(target) ?? [])]\n if (props.menu && editable.value && target.kind === 'task') {\n const ids = selected.value.has(target.task.id) ? selection.value : [target.task.id]\n const m = messages.value.menu\n items.push({\n key: 'remove',\n label: ids.length > 1 ? format(m.removeTasks, { count: ids.length }) : m.removeTask,\n icon: TrashIcon,\n shortcut: 'delete',\n tone: 'danger',\n divided: items.length > 0,\n run: () => removeTasks(ids),\n })\n }\n return items\n}\n\n/** Opens the menu at a point on screen; `false` when it has nothing to show. */\nfunction showMenu(on: SchedulerMenuTarget, x: number, y: number) {\n const start = on.kind === 'task' ? (itemById.value.get(on.task.id)?.item.span.start ?? 0) : 0\n const target = { ...on, time: timeAt(x, start) }\n const items = itemsFor(target)\n if (!items.length) return false\n if (target.kind === 'task') {\n active.value = target.task.id\n if (!selected.value.has(target.task.id)) selection.value = [target.task.id]\n }\n menuItems.value = items\n menu.value?.open(x, y)\n return true\n}\n\n/** When a finger last went down: its long press opens the menu itself, not the browser's. */\nlet touchedAt = 0\nconst onRootPointerdown = (event: PointerEvent) => {\n if (event.pointerType === 'touch') touchedAt = Date.now()\n}\n\n/**\n * A menu opened by a resting finger or by the menu key has no browser event:\n * it gets a stand-in, so `taskContextmenu` comes first in every case and\n * `preventDefault()` keeps the menu closed.\n */\nfunction menuAllowed(item: GanttTask, x: number, y: number) {\n const event = new MouseEvent('contextmenu', { cancelable: true, clientX: x, clientY: y })\n emit('taskContextmenu', item, event)\n return !event.defaultPrevented\n}\n\nfunction onTaskContextmenu(bar: Bar, event: MouseEvent) {\n // a finger's long press opens the menu, and sends the event, when it lets go\n if (Date.now() - touchedAt < 1000) return event.preventDefault()\n emit('taskContextmenu', bar.item.task, event)\n if (event.defaultPrevented) return\n if (showMenu(taskTarget(bar.item.task, bar.row), event.clientX, event.clientY))\n event.preventDefault()\n}\n\nfunction onBodyContextmenu(event: MouseEvent) {\n const target = event.target as HTMLElement\n if (event.defaultPrevented || target.closest('.dou-gantt__bar-row')) return\n if (Date.now() - touchedAt < 1000) return event.preventDefault()\n const row = resourceRowAt(contentY(event.clientY))\n if (!row) return\n const on = { kind: 'row', resource: row.resource, time: 0 } as const\n if (showMenu(on, event.clientX, event.clientY)) event.preventDefault()\n}\n\n/** The menu key, or Shift+F10, opens the menu of the task the keyboard is on, at its bar. */\nfunction openKeyMenu() {\n const found = active.value ? itemById.value.get(active.value) : undefined\n if (!found) return false\n const el = root.value?.querySelector(\n `.dou-gantt__bar[data-task=\"${CSS.escape(found.item.task.id)}\"]`,\n )\n const rect = el?.getBoundingClientRect()\n if (!rect) return false\n if (!menuAllowed(found.item.task, rect.left + 8, rect.bottom + 4)) return true\n return showMenu(taskTarget(found.item.task, found.row), rect.left + 8, rect.bottom + 4)\n}\n\n// Keys -------------------------------------------------------------------------------------\n\nconst keysHint = useId()\nconst live = ref('')\n\nfunction announce(text: string) {\n live.value = ''\n void nextTick(() => (live.value = text))\n}\n\n/** The tasks in reading order: row by row, by start. */\nconst ordered = computed(() => {\n const out: { item: SchedulerItem; row: ResourceRow; index: number }[] = []\n const list = rows.value.filter((row): row is ResourceRow => row.kind === 'resource')\n list.forEach((row, index) => {\n // oxlint-disable-next-line unicorn/no-array-sort -- sorts a fresh array\n const items = [...row.items].sort((a, b) => a.span.start - b.span.start || a.lane - b.lane)\n for (const item of items) out.push({ item, row, index })\n })\n return { out, rows: list }\n})\n\nfunction focusTask(id: string) {\n active.value = id\n scrollToTask(id)\n void nextTick(() => {\n const el = root.value?.querySelector<HTMLElement>(\n `.dou-gantt__bar[data-task=\"${CSS.escape(id)}\"]`,\n )\n ;(el ?? root.value)?.focus({ preventScroll: true })\n })\n}\n\nfunction scrollToTask(id: string) {\n const found = itemById.value.get(id)\n const el = chart.value\n if (!found || !el) return\n const top = laneTop(found.row, found.item.lane)\n if (top < el.scrollTop) el.scrollTop = top\n else if (top + props.rowHeight > el.scrollTop + bodyHeight.value)\n el.scrollTop = top + props.rowHeight - bodyHeight.value\n const left = xOf(found.item.span.start)\n const right = xOf(found.item.span.end)\n if (left < scrollLeft.value || right > scrollLeft.value + viewWidth.value)\n axis.scrollToTime(found.item.span.start)\n}\n\n/** Arrow keys: the next task along, or the one nearest in time in the row above or below. */\nfunction stepFocus(key: string) {\n const { out, rows: list } = ordered.value\n if (!out.length) return\n const at = out.findIndex((entry) => entry.item.task.id === active.value)\n if (at === -1) return void focusTask(out[0]!.item.task.id)\n const current = out[at]!\n if (key === 'ArrowLeft' || key === 'ArrowRight') {\n const next = out[at + (key === 'ArrowLeft' ? -1 : 1)]\n if (next && next.row === current.row) focusTask(next.item.task.id)\n return\n }\n const direction = key === 'ArrowUp' ? -1 : 1\n for (let i = current.index + direction; i >= 0 && i < list.length; i += direction) {\n const candidates = out.filter((entry) => entry.index === i)\n if (!candidates.length) continue\n const time = current.item.span.start\n let best = candidates[0]!\n for (const entry of candidates)\n if (Math.abs(entry.item.span.start - time) < Math.abs(best.item.span.start - time))\n best = entry\n return void focusTask(best.item.task.id)\n }\n}\n\n/** Alt and the arrow keys: earlier or later, or to the resource above or below. */\nfunction keyMove(key: string) {\n const found = active.value ? itemById.value.get(active.value) : undefined\n if (!found || found.item.task.locked) return\n const { item, row } = found\n const task = item.task\n if (key === 'ArrowLeft' || key === 'ArrowRight') {\n const unit = stepFor([item.span])\n const shift = key === 'ArrowLeft' ? -unit : unit\n const patch = writeSpan(task, item.span.start + shift, item.span.end + shift)\n const refusal = checkMove([{ id: task.id, patch }])\n if (refusal) return void announce(refusal)\n transact((tr) => tr.updateTask(task.id, patch), { group: `key-move:${task.id}` })\n const span = spanOf(taskById(task.id)!)\n if (span) announce(describe({ ...item, span }, row))\n return\n }\n const list = ordered.value.rows\n const index = list.indexOf(row)\n const target = list[index + (key === 'ArrowUp' ? -1 : 1)]\n if (!target) return\n const refusal = checkMove([{ id: task.id, patch: { resource: target.resource?.id } }])\n if (refusal) return void announce(refusal)\n transact((tr) => tr.updateTask(task.id, { resource: target.resource?.id }))\n announce(format(sm.value.moved, { title: task.title, resource: target.title }))\n focusTask(task.id)\n}\n\nfunction removeSelected() {\n const ids = selection.value.length ? selection.value : active.value ? [active.value] : []\n if (ids.length) removeTasks(ids)\n}\n\nfunction removeTasks(ids: string[]) {\n const titles = ids.map((id) => taskById(id)?.title).filter(Boolean)\n transact((tr) => {\n for (const id of ids) tr.removeTask(id)\n })\n active.value = null\n const m = messages.value\n announce(format(m.tasksRemoved, { titles: titles.join(m.listSeparator) }))\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (drag.value) return\n const key = event.key\n if (matchesHotkey(event, 'mod+z')) {\n event.preventDefault()\n if (editable.value) announceTravel('undo')\n return\n }\n if (matchesHotkey(event, 'mod+shift+z') || matchesHotkey(event, 'mod+y')) {\n event.preventDefault()\n if (editable.value) announceTravel('redo')\n return\n }\n if (key.startsWith('Arrow')) {\n event.preventDefault()\n if (event.altKey) {\n if (editable.value) keyMove(key)\n } else stepFocus(key)\n return\n }\n if (key === 'ContextMenu' || matchesHotkey(event, 'shift+f10')) {\n if (openKeyMenu()) event.preventDefault()\n return\n }\n if ((key === 'Delete' || key === 'Backspace') && editable.value) {\n event.preventDefault()\n removeSelected()\n return\n }\n if ((key === 'Enter' || key === ' ') && active.value) {\n event.preventDefault()\n const task = taskById(active.value)\n if (task) select(task, event)\n return\n }\n if (key === 'Escape' && selection.value.length) {\n event.preventDefault()\n selection.value = []\n }\n}\n\n// Exposed ------------------------------------------------------------------------------------\n\ndefineExpose<SchedulerExpose>({\n transact,\n undo,\n redo,\n get canUndo() {\n return canUndo.value\n },\n get canRedo() {\n return canRedo.value\n },\n fit: axis.fit,\n scrollToDate: axis.scrollToDate,\n scrollToToday: axis.scrollToToday,\n scrollToTask,\n focusTask,\n zoomIn: axis.zoomIn,\n zoomOut: axis.zoomOut,\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"dou-gantt is-scheduler\"\n :class=\"{\n 'is-narrow': narrow,\n 'is-editable': editable,\n 'is-dragging': drag?.started,\n [`is-dragging-${drag?.mode}`]: drag?.started,\n }\"\n :style=\"{ '--dou-gantt-row-height': `${rowHeight}px`, '--dou-gantt-lane': `${LANE}px` }\"\n role=\"group\"\n tabindex=\"0\"\n :aria-label=\"ariaLabel ?? sm.name\"\n :aria-describedby=\"keysHint\"\n @keydown=\"onKeydown\"\n @pointerdown.capture=\"onRootPointerdown\"\n >\n <span :id=\"keysHint\" class=\"dou-gantt__sr-only\">{{ sm.keys }}</span>\n <div class=\"dou-gantt__sr-only\" aria-live=\"polite\">{{ live }}</div>\n <div v-if=\"showTable\" class=\"dou-gantt__table-pane\" :style=\"{ width: `${tableSize}px` }\">\n <div class=\"dou-gantt__table\" role=\"list\" :aria-label=\"sm.resource\">\n <div class=\"dou-gantt__table-head\">\n <div class=\"dou-gantt__th is-title\">{{ sm.resource }}</div>\n </div>\n <div\n ref=\"tableBody\"\n class=\"dou-gantt__table-body\"\n tabindex=\"-1\"\n @scroll=\"axis.onTableScroll\"\n >\n <div class=\"dou-gantt__table-rows\" :style=\"{ height: `${totalHeight + scrollbar}px` }\">\n <div\n v-for=\"row in visibleRows\"\n :key=\"row.key\"\n class=\"dou-gantt__tr\"\n :class=\"{\n 'is-group': row.kind === 'group',\n 'is-hovered': hovered === row.key,\n 'is-overloaded': row.kind === 'resource' && row.overloaded,\n }\"\n :style=\"{ transform: `translateY(${row.top}px)`, height: `${row.height}px` }\"\n :data-row=\"row.key\"\n role=\"listitem\"\n :aria-label=\"row.kind === 'resource' ? describeRow(row) : row.title\"\n @pointerenter=\"hovered = row.key\"\n @pointerleave=\"hovered = null\"\n >\n <div class=\"dou-gantt__td is-title\">\n <template v-if=\"row.kind === 'group'\">\n <button\n type=\"button\"\n class=\"dou-gantt__toggle\"\n tabindex=\"-1\"\n :aria-label=\"collapsed.has(row.key) ? messages.expand : messages.collapse\"\n :aria-expanded=\"!collapsed.has(row.key)\"\n @click=\"toggle(row)\"\n >\n <component :is=\"collapsed.has(row.key) ? ChevronRightIcon : ChevronDownIcon\" />\n </button>\n <span class=\"dou-gantt__cell-text\">{{ row.title }}</span>\n </template>\n <template v-else>\n <span v-if=\"row.resource?.group\" class=\"dou-gantt__indent\" style=\"width: 16px\" />\n <span class=\"dou-gantt__toggle-space\" />\n <span class=\"dou-gantt__cell-text\" :class=\"{ 'is-unassigned': !row.resource }\">\n <slot v-if=\"row.resource\" name=\"resource\" :resource=\"row.resource\">\n {{ row.title }}\n </slot>\n <template v-else>{{ row.title }}</template>\n </span>\n <span\n v-if=\"row.overloaded\"\n class=\"dou-gantt__overload\"\n :title=\"sm.overloadHint\"\n aria-hidden=\"true\"\n />\n </template>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div\n ref=\"chart\"\n class=\"dou-gantt__chart\"\n :class=\"{ 'is-fixed': range }\"\n tabindex=\"-1\"\n @scroll.passive=\"axis.onChartScroll\"\n @wheel=\"axis.onWheel\"\n >\n <div class=\"dou-gantt__canvas\" :style=\"{ width: `${totalWidth}px` }\">\n <TimeHeader\n :top-cells=\"topCells\"\n :bottom-cells=\"bottomCells\"\n :bottom-unit=\"level.bottom\"\n :calendar=\"calendar\"\n :now=\"now\"\n :today-x=\"todayX\"\n >\n <span\n v-for=\"item in markers\"\n :key=\"item.key\"\n class=\"dou-gantt__marker-label\"\n :class=\"[\n item.marker.tone && `is-${item.marker.tone}`,\n { 'is-cut': item.room !== Infinity, 'is-crowded': !item.room },\n ]\"\n :title=\"item.room !== Infinity ? item.marker.label : undefined\"\n :style=\"{\n left: `${item.x}px`,\n maxWidth: item.room && item.room !== Infinity ? `${item.room}px` : undefined,\n }\"\n >\n <span v-if=\"item.marker.label\" class=\"dou-gantt__marker-text\">{{\n item.marker.label\n }}</span>\n </span>\n </TimeHeader>\n <div\n class=\"dou-gantt__body\"\n :style=\"{ height: `${totalHeight}px` }\"\n @pointerdown=\"onBodyDown\"\n @contextmenu=\"onBodyContextmenu\"\n >\n <div v-if=\"!showTable\" class=\"dou-gantt__row-titles\">\n <span\n v-for=\"row in rowTitles\"\n :key=\"row.key\"\n class=\"dou-gantt__row-title\"\n :class=\"{ 'is-summary': row.kind === 'group' }\"\n :style=\"{ transform: `translateY(${row.top}px)` }\"\n >\n <slot\n v-if=\"row.kind === 'resource' && row.resource\"\n name=\"resource\"\n :resource=\"row.resource\"\n >\n {{ row.title }}\n </slot>\n <template v-else>{{ row.title }}</template>\n </span>\n </div>\n <TimeGrid :cells=\"bottomCells\" :shaded=\"shaded\" />\n <div\n v-for=\"row in visibleRows\"\n :key=\"row.key\"\n class=\"dou-gantt__lane-row\"\n :class=\"{ 'is-group': row.kind === 'group', 'is-hovered': hovered === row.key }\"\n :style=\"{ transform: `translateY(${row.top}px)`, height: `${row.height}px` }\"\n />\n <div v-if=\"todayX != null\" class=\"dou-gantt__today\" :style=\"{ left: `${todayX}px` }\" />\n <div\n v-for=\"item in markers\"\n :key=\"item.key\"\n class=\"dou-gantt__marker\"\n :class=\"item.marker.tone && `is-${item.marker.tone}`\"\n :style=\"{ left: `${item.x}px` }\"\n />\n <div\n v-for=\"segment in loads\"\n :key=\"segment.key\"\n class=\"dou-gantt__load\"\n :class=\"{ 'is-over': segment.over }\"\n :style=\"{\n transform: `translate(${segment.left}px, ${segment.top}px)`,\n width: `${segment.width}px`,\n '--dou-gantt-load': segment.level,\n }\"\n />\n <div\n v-for=\"bar in bars\"\n :key=\"bar.item.task.id\"\n class=\"dou-gantt__bar-row\"\n :class=\"{\n 'is-selected': selected.has(bar.item.task.id),\n 'is-active': drag?.started && drag.spans.has(bar.item.task.id),\n }\"\n :style=\"{ transform: `translateY(${bar.top}px)` }\"\n >\n <div\n class=\"dou-gantt__bar\"\n :class=\"[\n bar.item.task.tone && `is-${bar.item.task.tone}`,\n {\n 'is-milestone': bar.milestone,\n 'is-selected': selected.has(bar.item.task.id),\n 'is-locked': bar.item.task.locked,\n 'is-active': active === bar.item.task.id,\n 'is-move-refused':\n !!dragRefusal && drag?.started && drag.spans.has(bar.item.task.id),\n },\n ]\"\n :data-task=\"bar.item.task.id\"\n :style=\"{\n left: `${bar.left}px`,\n width: bar.milestone ? undefined : `${bar.width}px`,\n }\"\n role=\"img\"\n tabindex=\"-1\"\n :aria-label=\"bar.aria\"\n @pointerdown=\"onBarDown($event, bar)\"\n @click=\"onTaskClick(bar.item.task, $event)\"\n @dblclick=\"emit('taskDblclick', bar.item.task, $event)\"\n @contextmenu=\"onTaskContextmenu(bar, $event)\"\n >\n <span v-if=\"!bar.outside\" class=\"dou-gantt__bar-label\">\n <slot name=\"bar\" :task=\"bar.item.task\">{{ bar.item.task.title }}</slot>\n </span>\n </div>\n <template v-if=\"editable && !bar.item.task.locked && !bar.milestone\">\n <span\n class=\"dou-gantt__handle is-start\"\n data-handle=\"start\"\n :style=\"{ left: `${bar.left}px` }\"\n @pointerdown=\"onBarDown($event, bar)\"\n />\n <span\n class=\"dou-gantt__handle is-end\"\n data-handle=\"end\"\n :style=\"{ left: `${bar.left + bar.width}px` }\"\n @pointerdown=\"onBarDown($event, bar)\"\n />\n </template>\n <span\n v-if=\"bar.outside\"\n class=\"dou-gantt__bar-side\"\n :style=\"{ left: `${bar.left + (bar.milestone ? 12 : bar.width + 8)}px` }\"\n >\n <slot name=\"bar\" :task=\"bar.item.task\">{{ bar.item.task.title }}</slot>\n </span>\n </div>\n <div\n v-if=\"drawnBox\"\n class=\"dou-gantt__ghost\"\n :style=\"{\n transform: `translate(${drawnBox.left}px, ${drawnBox.top}px)`,\n width: `${drawnBox.width}px`,\n }\"\n />\n <div\n v-if=\"dragTip\"\n class=\"dou-gantt__tip\"\n :class=\"{ 'is-refused': dragTip.refused }\"\n :style=\"{ transform: `translate(${dragTip.left}px, ${dragTip.top}px)` }\"\n >\n {{ dragTip.text }}\n </div>\n </div>\n </div>\n </div>\n <div\n v-if=\"showTable\"\n class=\"dou-gantt__divider\"\n role=\"separator\"\n :aria-label=\"messages.resizeTable\"\n tabindex=\"0\"\n aria-orientation=\"vertical\"\n :aria-valuenow=\"Math.round(tableSize)\"\n :aria-valuemin=\"TABLE_MIN\"\n :aria-valuemax=\"tableMax\"\n @pointerdown=\"onDividerDown\"\n @keydown=\"onDividerKey\"\n />\n <GanttMenu ref=\"menu\" v-model:open=\"menuOpen\" :items=\"menuItems\" />\n <slot />\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer dou.components{.dou-gantt{--dou-gantt-header-bg:var(--dou-color-bg-canvas);--dou-gantt-line:var(--dou-color-border-subtle);--dou-gantt-line-strong:var(--dou-color-border);--dou-gantt-off:color-mix(in oklab,var(--dou-color-text)5%,transparent);--dou-gantt-hover:color-mix(in oklab,var(--dou-color-text)3%,transparent);--dou-gantt-selected:color-mix(in oklab,var(--dou-color-primary)7%,transparent);--dou-gantt-link:color-mix(in oklab,var(--dou-color-text)32%,transparent);--dou-gantt-today:var(--dou-color-primary);--dou-gantt-bar-height:20px;position:relative;display:flex;box-sizing:border-box;overflow:hidden;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-container);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font-family:var(--dou-font-family);font-size:var(--dou-font-size-md);line-height:var(--dou-font-line-height);outline:none;width:100%;min-width:0;height:480px}.dou-gantt:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-gantt.is-dragging{user-select:none;-webkit-user-select:none}.dou-gantt.is-dragging *{user-select:none;-webkit-user-select:none}.dou-gantt.is-dragging-move{cursor:grabbing}.dou-gantt.is-dragging-move *{cursor:grabbing}.dou-gantt.is-dragging-start *{cursor:ew-resize}.dou-gantt.is-dragging-end *{cursor:ew-resize}.dou-gantt.is-dragging-progress *{cursor:ew-resize}.dou-gantt.is-dragging-draw *{cursor:ew-resize}.dou-gantt.is-dragging-link *{cursor:crosshair}.dou-gantt.is-dragging-row *{cursor:grabbing}.dou-gantt__table-pane{display:flex;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;flex:none;min-width:0}.dou-gantt__table{display:flex;flex-direction:column;flex:1 0 auto}.dou-gantt__table-head{display:flex;box-sizing:border-box;border-bottom:1px solid var(--dou-gantt-line-strong);background-color:var(--dou-gantt-header-bg);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);flex:none;height:56px}.dou-gantt__th,.dou-gantt__td{display:flex;box-sizing:border-box;white-space:nowrap;align-items: center;min-width:0;padding:0 12px}:is(.dou-gantt__th,.dou-gantt__td).is-center{justify-content:center}:is(.dou-gantt__th,.dou-gantt__td).is-end{justify-content:flex-end}.dou-gantt__th.is-title{min-width:120px}.dou-gantt__table-body{position:relative;overflow-x:hidden;overflow-y:auto;scrollbar-width:none;flex:1;min-height:0}.dou-gantt__table-body::-webkit-scrollbar{display:none}.dou-gantt__table-rows{position:relative}.dou-gantt__tr{position:absolute;display:flex;height:var(--dou-gantt-row-height);box-shadow:inset 0 -1px 0 var(--dou-gantt-line);cursor:default;top:0;left:0;right:0}.dou-gantt__tr.is-hovered{background-color:var(--dou-gantt-hover)}.dou-gantt__tr.is-selected{background-color:var(--dou-gantt-selected)}.dou-gantt__tr.is-summary .dou-gantt__td.is-title{font-weight:var(--dou-font-weight-medium)}.dou-gantt__td{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-gantt__td.is-title{color:var(--dou-color-text);font-size:var(--dou-font-size-md);min-width:120px;padding-left:6px}.dou-gantt__cell-text{overflow-x:clip;text-overflow:ellipsis;min-width:0}.dou-gantt__indent{flex:none}.dou-gantt__toggle,.dou-gantt__toggle-space{display:inline-flex;flex:none;justify-content:center;align-items: center;width:20px;height:20px;margin-right:4px}.dou-gantt__toggle{color:var(--dou-color-text-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;padding:0;font-size:14px}.dou-gantt__toggle:hover{background-color:var(--dou-color-bg-muted);color:var(--dou-color-text)}.dou-gantt__tr.is-moving{opacity:.45}.dou-gantt__tr.is-drop-inside{background-color:var(--dou-gantt-selected);box-shadow:inset 0 0 0 1px var(--dou-color-primary),inset 0 -1px 0 var(--dou-gantt-line)}.dou-gantt__drop-line{position:absolute;z-index:2;background-color:var(--dou-color-primary);pointer-events:none;border-radius:1px;height:2px;top:-1px;right:8px}.dou-gantt__add-row{position:absolute;display:flex;height:var(--dou-gantt-row-height);top:0;left:0;right:0}.dou-gantt__add-row>.dou-gantt__td{flex:1}.dou-gantt__add{display:inline-flex;text-align:start;border-radius:var(--dou-radius-control);color:var(--dou-color-text-tertiary);font:inherit;font-size:var(--dou-font-size-sm);cursor:pointer;background:0 0;border:0;flex:1;align-items: center;gap:6px;height:24px;margin-left:-6px;padding:0 6px}.dou-gantt__add>svg{font-size:14px}.dou-gantt__add:hover{background-color:var(--dou-color-bg-muted);color:var(--dou-color-text)}.dou-gantt__add:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:1px}.dou-gantt__editor{display:flex;flex:1;align-items: center;min-width:0}.dou-gantt__editor>*{flex:1;min-width:0}.dou-gantt__editor.is-date{position:absolute;z-index:3;width:156px;top:50%;left:6px;transform:translateY(-50%)}.dou-gantt__editor.is-datetime{position:absolute;z-index:3;width:156px;top:50%;left:6px;transform:translateY(-50%)}.dou-gantt__editor.is-datetime{width:208px}.dou-gantt__td{position:relative}.is-editable .dou-gantt__tr{user-select:none;-webkit-user-select:none}.dou-gantt__editor-input{box-sizing:border-box;border:1px solid var(--dou-color-border-strong,var(--dou-color-border));border-radius:var(--dou-radius-control);outline:none;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:max(var(--dou-font-size-input-min,0px),1em);width:100%;height:26px;margin-left:-7px;padding:0 6px}.dou-gantt__editor-input:focus{border-color:var(--dou-color-primary);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-focus)30%,transparent)}.dou-gantt__editor-input::placeholder{color:var(--dou-color-text-tertiary)}.dou-gantt__editor-input[aria-invalid=true]{border-color:var(--dou-color-danger);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-danger)24%,transparent)}.dou-gantt__menu-anchor{position:absolute;overflow:hidden;width:0;height:0}.dou-gantt__divider{position:relative;z-index:3;background-color:var(--dou-gantt-line-strong);outline:none;touch-action:none;cursor:col-resize;transition:background-color var(--dou-motion-duration-fast)var(--dou-motion-easing);flex:none;order:1;width:1px}.dou-gantt__divider:before{position:absolute;content:"";inset:0 -4px}.dou-gantt__divider:hover{background-color:var(--dou-color-focus)}.dou-gantt__divider:focus-visible{background-color:var(--dou-color-focus)}.dou-gantt__chart{position:relative;overflow:auto;outline:none;overscroll-behavior-x:none;flex:1;order:2;min-width:0}.dou-gantt__chart.is-fixed{overscroll-behavior-x:contain}.dou-gantt__canvas{position:relative;min-height:100%}.dou-gantt__header{position:sticky;z-index:4;box-sizing:border-box;border-bottom:1px solid var(--dou-gantt-line-strong);background-color:var(--dou-gantt-header-bg);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;height:56px;top:0}.dou-gantt__tier{position:relative;overflow:clip;height:28px}.dou-gantt__tier.is-top{box-shadow:inset 0 -1px 0 var(--dou-gantt-line);color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.dou-gantt__tier.is-bottom{height:27px}.dou-gantt__cell{position:absolute;display:flex;box-sizing:border-box;box-shadow:inset 1px 0 0 var(--dou-gantt-line);align-items: center;top:0;bottom:0}.is-bottom>.dou-gantt__cell{justify-content:center}.dou-gantt__cell-label{position:sticky;overflow-x:clip;text-overflow:ellipsis;text-box:trim-both cap alphabetic;margin-block-start:-4px;margin-block-end:-4px;padding:4px 8px;left:0}.dou-gantt__cell.is-off{color:var(--dou-color-text-tertiary)}.dou-gantt__cell.is-now{color:var(--dou-gantt-today);font-weight:var(--dou-font-weight-medium)}.dou-gantt__today-mark{position:absolute;background-color:var(--dou-gantt-today);clip-path:polygon(50% 0,100% 100%,0 100%);width:8px;height:4px;margin-left:-3.5px;bottom:-1px}.dou-gantt__body{position:relative;background-image:linear-gradient(to top,var(--dou-gantt-line)1px,transparent 1px);background-size:100% var(--dou-gantt-row-height)}.dou-gantt__row-titles{position:sticky;z-index:3;overflow:visible;width:0;height:0;left:0}.dou-gantt__row-title{position:absolute;display:flex;height:var(--dou-gantt-row-height);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;pointer-events:none;text-shadow:0 0 2px var(--dou-color-bg-surface),0 0 2px var(--dou-color-bg-surface),0 0 4px var(--dou-color-bg-surface);align-items: center;padding:0 12px;top:0;left:0}.dou-gantt__row-title.is-summary{color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.dou-gantt__off,.dou-gantt__gridline,.dou-gantt__today{position:absolute;pointer-events:none;top:0;bottom:0}.dou-gantt__off{background-color:var(--dou-gantt-off)}.dou-gantt__gridline{background-color:var(--dou-gantt-line);width:1px}.dou-gantt__today{z-index:1;background-color:var(--dou-gantt-today);width:1px}.dou-gantt__row-highlight{position:absolute;height:var(--dou-gantt-row-height);background-color:var(--dou-gantt-hover);pointer-events:none;top:0;left:0;right:0}.dou-gantt__row-highlight.is-selected{background-color:var(--dou-gantt-selected)}.dou-gantt__links{position:absolute;z-index:1;overflow:visible;pointer-events:none;top:0;left:0}.dou-gantt__link{color:var(--dou-gantt-link)}.dou-gantt__link:hover{color:var(--dou-color-primary)}.dou-gantt__link.is-related{color:var(--dou-color-primary)}.dou-gantt__link-hit{fill:none;stroke:transparent;stroke-width:10px;pointer-events:stroke}.dou-gantt__link-line{fill:none;stroke:currentColor;stroke-width:1px}.dou-gantt__link-arrow{fill:currentColor}.dou-gantt__link.is-selected{color:var(--dou-color-primary)}.dou-gantt__link.is-selected .dou-gantt__link-line{stroke-width:2px}.dou-gantt__link.is-critical{color:color-mix(in oklab,var(--dou-color-danger)72%,var(--dou-color-bg-surface))}.dou-gantt__link.is-broken{color:var(--dou-color-warning)}.dou-gantt__link.is-broken .dou-gantt__link-line{stroke-dasharray:4 3}.dou-gantt__link-draft{fill:none;stroke:var(--dou-color-primary);stroke-dasharray:4 3;stroke-width:1.5px}.dou-gantt__link-draft.is-refused{stroke:var(--dou-color-danger)}.dou-gantt__bar-row{position:absolute;z-index:2;height:var(--dou-gantt-row-height);top:0;left:0}.dou-gantt__bar{--dou-gantt-tone:var(--dou-color-text);position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2);display:flex;box-sizing:border-box;height:var(--dou-gantt-bar-height);overflow:clip;border:1px solid color-mix(in oklab,var(--dou-gantt-tone)18%,var(--dou-color-bg-surface));background-color:color-mix(in oklab,var(--dou-gantt-tone)5%,var(--dou-color-bg-surface));box-shadow:var(--dou-shadow-sm);cursor:default;border-radius:6px;align-items: center}.dou-gantt__bar:hover{border-color:color-mix(in oklab,var(--dou-gantt-tone)34%,var(--dou-color-bg-surface))}.is-editable .dou-gantt__bar:not(.is-locked){cursor:grab}.dou-gantt__bar.is-link-target{border-color:var(--dou-color-primary);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-primary)22%,transparent)}.dou-gantt__bar.is-link-refused{border-color:var(--dou-color-danger);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-danger)18%,transparent)}.dou-gantt__bar.is-move-refused{border-color:var(--dou-color-danger);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-danger)18%,transparent)}.dou-gantt__bar.is-selected{border-color:var(--dou-color-primary);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-focus)35%,transparent)}.dou-gantt__bar.is-primary{--dou-gantt-tone:var(--dou-color-primary)}.dou-gantt__bar.is-success{--dou-gantt-tone:var(--dou-color-success)}.dou-gantt__bar.is-warning{--dou-gantt-tone:var(--dou-color-warning)}.dou-gantt__bar.is-danger{--dou-gantt-tone:var(--dou-color-danger)}.dou-gantt__bar.is-critical{--dou-gantt-tone:var(--dou-color-danger)}.dou-gantt__bar.is-critical:not(:-webkit-any(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt__bar.is-critical:not(:-moz-any(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt__bar.is-critical:not(:is(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt.has-baseline :-webkit-any(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt.has-baseline :-moz-any(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt.has-baseline :is(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt__baseline{--dou-gantt-baseline:color-mix(in oklab,var(--dou-color-text)24%,var(--dou-color-bg-surface));position:absolute;top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 2px);z-index:1;background-color:var(--dou-gantt-baseline);pointer-events:none;border-radius:2px;height:4px;left:0}.dou-gantt__baseline.is-milestone{top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 4px);border-radius:1px;width:8px;height:8px;margin-left:-4px}.dou-gantt__ghost{position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2);z-index:2;box-sizing:border-box;height:var(--dou-gantt-bar-height);border:1px dashed color-mix(in oklab,var(--dou-color-text)40%,transparent);pointer-events:none;border-radius:6px;left:0}.dou-gantt__ghost.is-milestone{top:calc((var(--dou-gantt-row-height) - 10px)/2);border-radius:2px;width:10px;height:10px;margin-left:-5px}.dou-gantt__peer{--dou-gantt-peer-color:var(--dou-color-text-secondary);position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2 - 2px);z-index:2;box-sizing:content-box;height:var(--dou-gantt-bar-height);border:1px solid var(--dou-gantt-peer-color);pointer-events:none;border-radius:8px;padding:1px;left:-2px}.dou-gantt__peer.is-moving{background-color:color-mix(in oklab,var(--dou-gantt-peer-color)8%,transparent);border-style:dashed}.dou-gantt__peer.is-milestone{top:calc((var(--dou-gantt-row-height) - 14px)/2 - 2px);border-radius:3px;width:14px;height:14px;margin-left:-9px}.dou-gantt__peer.is-milestone>.dou-gantt__peer-name{transform-origin:0 0;top:100%;left:0;right:auto;transform:rotate(-45deg)translate(calc(-100% - 4px),-50%);translate:none}.dou-gantt__peer.is-milestone.is-moving>.dou-gantt__peer-name{top:0;left:100%;transform:rotate(-45deg)translate(4px,-50%)}.dou-gantt__peer.is-moving>.dou-gantt__peer-name{left:calc(100% + 4px);right:auto}.dou-gantt__peer-name{position:absolute;background-color:var(--dou-gantt-peer-color);color:oklch(from var(--dou-gantt-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;padding:0 6px;line-height:18px;top:50%;right:calc(100% + 4px);translate:0 -50%}.dou-gantt__progress{position:absolute;background-color:color-mix(in oklab,var(--dou-gantt-tone)12%,var(--dou-color-bg-surface));top:0;bottom:0;left:0}.dou-gantt__bar-label{position:sticky;overflow-x:clip;font-size:var(--dou-font-size-sm);text-overflow:ellipsis;white-space:nowrap;text-box:trim-both cap alphabetic;min-width:0;margin-block-start:-4px;margin-block-end:-4px;padding:4px 8px;left:0}.dou-gantt__bar.is-summary{top:calc((var(--dou-gantt-row-height) - 8px)/2 - 2px);overflow:visible;background-color:color-mix(in oklab,var(--dou-gantt-tone)40%,var(--dou-color-bg-surface));box-shadow:none;border:0;border-radius:2px 2px 0 0;height:6px}.dou-gantt__bar.is-summary:before{position:absolute;background-color:inherit;content:"";width:6px;height:5px;top:100%}.dou-gantt__bar.is-summary:after{position:absolute;background-color:inherit;content:"";width:6px;height:5px;top:100%}.dou-gantt__bar.is-summary:before{clip-path:polygon(0 0,100% 0,0 100%);left:0}.dou-gantt__bar.is-summary:after{clip-path:polygon(0 0,100% 0,100% 100%);right:0}.dou-gantt__bar.is-summary.is-selected{background-color:var(--dou-color-primary);box-shadow:none}.dou-gantt__bar.is-milestone{top:calc((var(--dou-gantt-row-height) - 10px)/2);border-color:color-mix(in oklab,var(--dou-gantt-tone)70%,var(--dou-color-bg-surface));background-color:color-mix(in oklab,var(--dou-gantt-tone)62%,var(--dou-color-bg-surface));border-radius:2px;width:10px;height:10px;margin-left:-5px;transform:rotate(45deg)}.dou-gantt__bar.is-milestone.is-selected{border-color:var(--dou-color-primary);background-color:var(--dou-color-primary)}.dou-gantt__bar-side{position:absolute;display:flex;height:var(--dou-gantt-row-height);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;pointer-events:none;text-shadow:0 0 2px var(--dou-color-bg-surface),0 0 2px var(--dou-color-bg-surface),0 0 4px var(--dou-color-bg-surface);align-items: center;top:0}.dou-gantt__bar-side.is-summary{color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.is-editable .dou-gantt__bar-row:-webkit-any(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.is-editable .dou-gantt__bar-row:-moz-any(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.is-editable .dou-gantt__bar-row:is(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot{position:absolute;z-index:1;opacity:0;touch-action:none;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-gantt__bar-row:hover>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.dou-gantt__bar-row.is-selected>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.dou-gantt__bar-row.is-active>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.is-dragging .dou-gantt__bar-row:not(.is-active)>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:0}.dou-gantt__handle{top:calc((var(--dou-gantt-row-height) - 12px)/2);cursor:ew-resize;width:12px;height:12px;margin-left:-6px}.dou-gantt__handle:after{position:absolute;background-color:color-mix(in oklab,var(--dou-color-text)40%,transparent);content:"";border-radius:1px;width:2px;height:8px;top:2px;left:5px}.dou-gantt__handle.is-start:after{left:7px}.dou-gantt__handle.is-end:after{left:3px}.dou-gantt__progress-handle{top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 1px);cursor:ew-resize;width:12px;height:10px;margin-left:-6px}.dou-gantt__progress-handle:after{position:absolute;background-color:color-mix(in oklab,var(--dou-color-text)45%,transparent);clip-path:polygon(50% 0,100% 100%,0 100%);content:"";width:8px;height:6px;top:2px;left:2px}.dou-gantt__dot{top:calc((var(--dou-gantt-row-height) - 16px)/2);cursor:crosshair;width:16px;height:16px;margin-left:-8px}.dou-gantt__dot.is-start{transform:translate(-10px)}.dou-gantt__dot.is-end{transform:translate(10px)}.dou-gantt__dot:after{position:absolute;box-sizing:border-box;border:1px solid color-mix(in oklab,var(--dou-color-text)45%,transparent);background-color:var(--dou-color-bg-surface);content:"";border-radius:50%;inset:4px}.dou-gantt__dot:hover:after{border-color:var(--dou-color-primary);background-color:var(--dou-color-primary)}@media (pointer:coarse){.dou-gantt__bar-row:not(.is-selected)>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){display:none}.dou-gantt__handle{top:calc((var(--dou-gantt-row-height) - 32px)/2);width:32px;height:32px;margin-left:-16px}.dou-gantt__handle:after{top:12px;left:15px}.dou-gantt__handle.is-start:after{left:19px}.dou-gantt__handle.is-end:after{left:11px}.dou-gantt__dot{top:calc((var(--dou-gantt-row-height) - 32px)/2);width:32px;height:32px;margin-left:-16px}.dou-gantt__dot:after{inset:11px}.dou-gantt__dot.is-start{transform:translate(-20px)}.dou-gantt__dot.is-end{transform:translate(20px)}}.dou-gantt__tip{position:absolute;z-index:4;display:flex;border-radius:var(--dou-radius-control);background-color:var(--dou-color-neutral);box-shadow:var(--dou-shadow-md);color:var(--dou-color-neutral-on);white-space:nowrap;pointer-events:none;align-items: center;height:22px;padding:0 8px;font-size:12px;top:-26px;left:0}.dou-gantt__tip.is-refused{background-color:var(--dou-color-danger);color:var(--dou-color-danger-on)}.dou-gantt__bar:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-gantt__tr:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:-2px}.dou-gantt__notice{position:absolute;z-index:20;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);box-shadow:var(--dou-shadow-md);color:var(--dou-color-text);font-size:var(--dou-font-size-sm);pointer-events:none;width:max-content;max-width:calc(100% - 24px);padding:6px 12px;bottom:12px;left:50%;transform:translate(-50%)}.dou-gantt__sr-only{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-gantt__marker,.dou-gantt__marker-label{--dou-gantt-marker:color-mix(in oklab,var(--dou-color-text)45%,transparent);--dou-gantt-marker-text:var(--dou-color-text-secondary)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-primary{--dou-gantt-marker:var(--dou-color-primary);--dou-gantt-marker-text:var(--dou-color-primary-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-success{--dou-gantt-marker:var(--dou-color-success);--dou-gantt-marker-text:var(--dou-color-success-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-warning{--dou-gantt-marker:var(--dou-color-warning);--dou-gantt-marker-text:var(--dou-color-warning-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-danger{--dou-gantt-marker:var(--dou-color-danger);--dou-gantt-marker-text:var(--dou-color-danger-text)}.dou-gantt__marker{position:absolute;z-index:1;border-left:1px dashed var(--dou-gantt-marker);pointer-events:none;top:0;bottom:0}.dou-gantt__marker-label{position:absolute;z-index:1;display:flex;border:1px solid color-mix(in oklab,var(--dou-gantt-marker)40%,transparent);border-radius:var(--dou-radius-control);background-color:var(--dou-gantt-header-bg);color:var(--dou-gantt-marker-text);box-sizing:border-box;white-space:nowrap;pointer-events:none;align-items: center;height:18px;padding:0 6px;font-size:12px;top:5px;transform:translate(4px)}.dou-gantt__marker-label.is-cut{pointer-events:auto}.dou-gantt__marker-label.is-crowded{background-color:#0000;border-color:#0000;width:12px;padding:0}.dou-gantt__marker-label.is-crowded>.dou-gantt__marker-text{display:none}.dou-gantt__marker-label:before{position:absolute;border-left:1px dashed var(--dou-gantt-marker);content:"";height:56px;top:-6px;left:-5px}.dou-gantt__marker-label:empty{display:none}.dou-gantt__marker-text{overflow:hidden;text-overflow:ellipsis;min-width:0}.dou-gantt.is-scheduler .dou-gantt__body{background-image:none}.is-scheduler .dou-gantt__row-title:not(.is-summary){gap:6px;height:16px;padding:0 12px;font-size:12px;top:2px}.dou-gantt__lane-row{position:absolute;box-shadow:inset 0 -1px 0 var(--dou-gantt-line);pointer-events:none;top:0;left:0;right:0}.dou-gantt__lane-row.is-hovered{background-color:var(--dou-gantt-hover)}.dou-gantt__lane-row.is-group{background-color:var(--dou-gantt-hover)}.is-scheduler .dou-gantt__tr{align-items: flex-start}.is-scheduler .dou-gantt__tr>.dou-gantt__td{height:var(--dou-gantt-row-height)}.is-scheduler .dou-gantt__tr.is-group{background-color:var(--dou-gantt-hover);font-weight:var(--dou-font-weight-medium)}.dou-gantt__overload{display:grid;flex:none;place-items: center;width:16px;height:16px;margin-left:2px}.dou-gantt__overload:before{background-color:var(--dou-color-warning);content:"";border-radius:50%;width:6px;height:6px}.dou-gantt__cell-text.is-unassigned{color:var(--dou-color-text-secondary)}.dou-gantt__load{--dou-gantt-load:1;position:absolute;z-index:1;background-color:color-mix(in oklab,var(--dou-color-text)calc(6% + 14%*var(--dou-gantt-load)),transparent);pointer-events:none;border-radius:2px;height:4px;top:0;left:0}.dou-gantt__load.is-over{background-color:var(--dou-color-warning)}@media print{.dou-gantt{print-color-adjust:exact;-webkit-print-color-adjust:exact}.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__tip,.dou-gantt__divider{display:none}}}
|
package/dist/style.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/style.js
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { MINUTES_PER_DAY, dayStart, parseTime, wallClockNow } from "./core/time.js";
|
|
2
|
+
import { offTime } from "./core/calendar.js";
|
|
3
|
+
import { DAY_WIDTH_RANGE, hourStep, levelByName, levelOf, unitStart, unitsBetween } from "./core/scale.js";
|
|
4
|
+
import { unitLabel } from "./labels.js";
|
|
5
|
+
import { createScrollLink, scrollPositionOf, useNow, useTouchScroll } from "dou-ui";
|
|
6
|
+
import { computed, onMounted, ref, watch } from "vue";
|
|
7
|
+
// src/time-axis.ts
|
|
8
|
+
/** Room around the visible part that is rendered too, in px. */
|
|
9
|
+
var OVERSCAN_X = 320;
|
|
10
|
+
/** The widest a day gets when fitting, so short plans don't zoom to hours. */
|
|
11
|
+
var FIT_MAX = 64;
|
|
12
|
+
var ZOOM_STEP = 1.5;
|
|
13
|
+
/**
|
|
14
|
+
* Room kept before the view on a touch screen, in screens and at least in
|
|
15
|
+
* px, but no more time than `ROOM_BEFORE_TIME`. Time can only be added there
|
|
16
|
+
* once a touch scroll is over, so it is enough for a long run of fast swipes
|
|
17
|
+
* that never lets the momentum stop. Only what is in view is drawn, so room
|
|
18
|
+
* costs nothing but scroll width.
|
|
19
|
+
*/
|
|
20
|
+
var ROOM_BEFORE = 300;
|
|
21
|
+
var ROOM_BEFORE_MIN = 4e5;
|
|
22
|
+
/** Ten thousand years, in minutes: room for a run of swipes at the widest scale too. */
|
|
23
|
+
var ROOM_BEFORE_TIME = 365e4 * MINUTES_PER_DAY;
|
|
24
|
+
/** The earliest the timeline goes, some 190,000 years back, well within what a date can be. */
|
|
25
|
+
var EARLIEST = -1e11;
|
|
26
|
+
/**
|
|
27
|
+
* Room kept before the view with a mouse or trackpad, in screens. It is
|
|
28
|
+
* filled as soon as the view comes near the start, and stays small so the
|
|
29
|
+
* scrollbar thumb still shows where the view is.
|
|
30
|
+
*/
|
|
31
|
+
var ROOM_BEFORE_POINTER = 4;
|
|
32
|
+
/** Room kept after the view, in screens; time is added there as you scroll. */
|
|
33
|
+
var ROOM_AFTER = 4;
|
|
34
|
+
function fingers(event) {
|
|
35
|
+
const [a, b] = [event.touches[0], event.touches[1]];
|
|
36
|
+
return {
|
|
37
|
+
a,
|
|
38
|
+
b,
|
|
39
|
+
distance: Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The time axis the gantt chart and the scheduler share: zoom, the extent
|
|
44
|
+
* that grows as you scroll, the header cells, days off and the today line.
|
|
45
|
+
*/
|
|
46
|
+
function useTimeAxis(o) {
|
|
47
|
+
/** How wide a day is, in px; zooming changes it smoothly. */
|
|
48
|
+
const dayWidth = ref(levelByName(o.scale.value ?? "day").base);
|
|
49
|
+
/** Without a `scale`, the first view picks the day width that fits the content. */
|
|
50
|
+
let fitPending = o.scale.value == null;
|
|
51
|
+
const level = computed(() => levelOf(dayWidth.value));
|
|
52
|
+
/** px per minute. */
|
|
53
|
+
const ppm = computed(() => dayWidth.value / MINUTES_PER_DAY);
|
|
54
|
+
watch(level, (next) => {
|
|
55
|
+
if (o.scale.value !== next.name) o.scale.value = next.name;
|
|
56
|
+
});
|
|
57
|
+
watch(o.scale, (name) => {
|
|
58
|
+
if (!name || level.value.name === name) return;
|
|
59
|
+
const x = todayX.value == null ? null : todayX.value - scrollLeft.value;
|
|
60
|
+
zoomTo(levelByName(name).base, x != null && x >= 0 && x <= o.viewWidth.value ? x : void 0);
|
|
61
|
+
});
|
|
62
|
+
const nowMs = useNow({ interval: 6e4 });
|
|
63
|
+
const now = computed(() => wallClockNow(new Date(nowMs.value)));
|
|
64
|
+
/** The content's time, or the coming month when nothing is scheduled. */
|
|
65
|
+
const content = computed(() => {
|
|
66
|
+
const known = o.content.value;
|
|
67
|
+
if (known) return known;
|
|
68
|
+
const start = dayStart(now.value);
|
|
69
|
+
return {
|
|
70
|
+
start,
|
|
71
|
+
end: start + 30 * MINUTES_PER_DAY
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
/** The furthest the view has gone either way, so the timeline keeps it. */
|
|
75
|
+
const reach = ref(null);
|
|
76
|
+
/** px of room kept before the view. */
|
|
77
|
+
/** Whether there is a touch screen; read once mounted, so the server render matches. */
|
|
78
|
+
const coarse = ref(false);
|
|
79
|
+
const roomBefore = computed(() => {
|
|
80
|
+
const width = o.viewWidth.value || 800;
|
|
81
|
+
if (!coarse.value) return ROOM_BEFORE_POINTER * width;
|
|
82
|
+
return Math.min(Math.max(ROOM_BEFORE * width, ROOM_BEFORE_MIN), ROOM_BEFORE_TIME * ppm.value);
|
|
83
|
+
});
|
|
84
|
+
const touch = useTouchScroll();
|
|
85
|
+
/** Where the timeline would start, without a fixed range. */
|
|
86
|
+
const freeStart = computed(() => {
|
|
87
|
+
const start = Math.min(content.value.start, reach.value?.start ?? Infinity);
|
|
88
|
+
return Math.max(EARLIEST, dayStart(start - roomBefore.value / ppm.value));
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* The start held while a touch scroll goes on. A later start moves the
|
|
92
|
+
* content, and the scroll position has to follow it, which iOS drops then:
|
|
93
|
+
* content coming in earlier, the room changing as the screen turns. So the
|
|
94
|
+
* start stays where it was and moves once the scroll is over.
|
|
95
|
+
*/
|
|
96
|
+
const heldStart = ref(null);
|
|
97
|
+
watch(touch.active, (on) => {
|
|
98
|
+
heldStart.value = on ? freeStart.value : null;
|
|
99
|
+
}, { flush: "sync" });
|
|
100
|
+
/** The span the timeline covers. */
|
|
101
|
+
const extent = computed(() => {
|
|
102
|
+
const fixed = o.range()?.map((text) => parseTime(text));
|
|
103
|
+
if (fixed?.[0] && fixed[1]) return {
|
|
104
|
+
start: dayStart(fixed[0].at),
|
|
105
|
+
end: dayStart(fixed[1].at) + MINUTES_PER_DAY
|
|
106
|
+
};
|
|
107
|
+
const width = o.viewWidth.value || 800;
|
|
108
|
+
const after = Math.max(ROOM_AFTER * width / ppm.value, 7 * MINUTES_PER_DAY);
|
|
109
|
+
const end = Math.max(content.value.end, reach.value?.end ?? -Infinity);
|
|
110
|
+
return {
|
|
111
|
+
start: heldStart.value ?? freeStart.value,
|
|
112
|
+
end: dayStart(end + after) + MINUTES_PER_DAY
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
const origin = computed(() => extent.value.start);
|
|
116
|
+
const totalWidth = computed(() => Math.ceil((extent.value.end - extent.value.start) * ppm.value));
|
|
117
|
+
const xOf = (at) => (at - origin.value) * ppm.value;
|
|
118
|
+
const scrollTop = ref(0);
|
|
119
|
+
const scrollLeft = ref(0);
|
|
120
|
+
/**
|
|
121
|
+
* The time at the left edge of the view. It is what stays put: when the
|
|
122
|
+
* extent grows or the zoom changes, the scroll position follows it.
|
|
123
|
+
*/
|
|
124
|
+
const viewStart = ref(0);
|
|
125
|
+
const scrollbar = ref(0);
|
|
126
|
+
const link = createScrollLink("y");
|
|
127
|
+
function onChartScroll() {
|
|
128
|
+
const el = o.chart.value;
|
|
129
|
+
const body = o.tableBody.value;
|
|
130
|
+
const { top, left } = scrollPositionOf(el);
|
|
131
|
+
scrollTop.value = top;
|
|
132
|
+
scrollLeft.value = left;
|
|
133
|
+
viewStart.value = origin.value + left / ppm.value;
|
|
134
|
+
if (body) link.follow(el, body);
|
|
135
|
+
grow();
|
|
136
|
+
}
|
|
137
|
+
/** Keeps time `at` on the timeline, adding room around it. */
|
|
138
|
+
function keep(at, until = at) {
|
|
139
|
+
const known = reach.value;
|
|
140
|
+
const start = Math.min(known?.start ?? at, at);
|
|
141
|
+
const end = Math.max(known?.end ?? until, until);
|
|
142
|
+
if (known?.start !== start || known.end !== end) reach.value = {
|
|
143
|
+
start,
|
|
144
|
+
end
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Adds time at the end the view comes near. After the end that is safe at
|
|
149
|
+
* any time. Before the start it moves the content right, and the scroll
|
|
150
|
+
* position has to follow it; iOS drops that move while a touch scroll or
|
|
151
|
+
* its momentum goes on, and the next scroll event would read the old
|
|
152
|
+
* position against the new start. So the room before is wide enough for a
|
|
153
|
+
* run of swipes, and is filled again once the scroll is over.
|
|
154
|
+
*/
|
|
155
|
+
function grow() {
|
|
156
|
+
const el = o.chart.value;
|
|
157
|
+
if (!el || o.range()) return;
|
|
158
|
+
const width = o.viewWidth.value;
|
|
159
|
+
const left = scrollPositionOf(el).left;
|
|
160
|
+
if (left + width > totalWidth.value - ROOM_AFTER * width) keep(viewStart.value, viewStart.value + 5 * width / ppm.value);
|
|
161
|
+
if (touch.active.value) touch.whenSettled(growBefore);
|
|
162
|
+
else if (left < 2 * width) growBefore();
|
|
163
|
+
}
|
|
164
|
+
function growBefore() {
|
|
165
|
+
const el = o.chart.value;
|
|
166
|
+
if (!el || o.range() || el.scrollLeft < 0) return;
|
|
167
|
+
if (scrollPositionOf(el).left < roomBefore.value - o.viewWidth.value) keep(viewStart.value);
|
|
168
|
+
}
|
|
169
|
+
function onTableScroll() {
|
|
170
|
+
const body = o.tableBody.value;
|
|
171
|
+
const el = o.chart.value;
|
|
172
|
+
if (el) link.follow(body, el);
|
|
173
|
+
}
|
|
174
|
+
watch([
|
|
175
|
+
origin,
|
|
176
|
+
ppm,
|
|
177
|
+
totalWidth
|
|
178
|
+
], () => {
|
|
179
|
+
const el = o.chart.value;
|
|
180
|
+
if (!el) return;
|
|
181
|
+
const target = Math.round((viewStart.value - origin.value) * ppm.value);
|
|
182
|
+
if (Math.abs(el.scrollLeft - target) >= 1) el.scrollLeft = target;
|
|
183
|
+
scrollLeft.value = scrollPositionOf(el).left;
|
|
184
|
+
}, { flush: "post" });
|
|
185
|
+
function measureScrollbar() {
|
|
186
|
+
const el = o.chart.value;
|
|
187
|
+
if (el) scrollbar.value = el.offsetHeight - el.clientHeight;
|
|
188
|
+
}
|
|
189
|
+
function scrollToTime(at, offset = 48) {
|
|
190
|
+
const target = at - offset / ppm.value;
|
|
191
|
+
viewStart.value = unitStart(level.value.bottom, target, o.weekStart.value, headerStep.value);
|
|
192
|
+
if (!o.range()) keep(viewStart.value, viewStart.value + o.viewWidth.value / ppm.value);
|
|
193
|
+
const el = o.chart.value;
|
|
194
|
+
if (!el) return;
|
|
195
|
+
el.scrollLeft = Math.round((viewStart.value - origin.value) * ppm.value);
|
|
196
|
+
scrollLeft.value = scrollPositionOf(el).left;
|
|
197
|
+
}
|
|
198
|
+
function fit() {
|
|
199
|
+
const width = o.fitWidth();
|
|
200
|
+
if (!width) return;
|
|
201
|
+
const days = Math.max(1, (content.value.end - content.value.start) / MINUTES_PER_DAY);
|
|
202
|
+
dayWidth.value = Math.min(FIT_MAX, Math.max(DAY_WIDTH_RANGE[0], (width - 96) / days));
|
|
203
|
+
scrollToTime(content.value.start);
|
|
204
|
+
}
|
|
205
|
+
onMounted(() => {
|
|
206
|
+
coarse.value = window.matchMedia?.("(any-pointer: coarse)").matches ?? false;
|
|
207
|
+
measureScrollbar();
|
|
208
|
+
scrollToTime(content.value.start);
|
|
209
|
+
});
|
|
210
|
+
/** Fits the content once the timeline has a width, unless a `scale` was given. */
|
|
211
|
+
function fitWhenSized() {
|
|
212
|
+
if (!fitPending || !o.fitWidth() || !o.viewWidth.value) return;
|
|
213
|
+
fitPending = false;
|
|
214
|
+
fit();
|
|
215
|
+
}
|
|
216
|
+
/** Changes the day width, keeping the time under `anchor` (px from the view's left) in place. */
|
|
217
|
+
function zoomTo(width, anchor = o.viewWidth.value / 2) {
|
|
218
|
+
const next = Math.min(DAY_WIDTH_RANGE[1], Math.max(DAY_WIDTH_RANGE[0], width));
|
|
219
|
+
const at = viewStart.value + anchor / ppm.value;
|
|
220
|
+
dayWidth.value = next;
|
|
221
|
+
viewStart.value = at - anchor / ppm.value;
|
|
222
|
+
if (reach.value && !o.range()) {
|
|
223
|
+
reach.value = null;
|
|
224
|
+
keep(viewStart.value, viewStart.value + o.viewWidth.value / ppm.value);
|
|
225
|
+
}
|
|
226
|
+
if (heldStart.value != null) heldStart.value = freeStart.value;
|
|
227
|
+
}
|
|
228
|
+
function onWheel(event) {
|
|
229
|
+
if (!(event.ctrlKey || event.metaKey)) return;
|
|
230
|
+
event.preventDefault();
|
|
231
|
+
const rect = o.chart.value.getBoundingClientRect();
|
|
232
|
+
zoomTo(dayWidth.value * Math.exp(-event.deltaY * .01), event.clientX - rect.left);
|
|
233
|
+
}
|
|
234
|
+
const zoomIn = () => zoomTo(dayWidth.value * ZOOM_STEP);
|
|
235
|
+
const zoomOut = () => zoomTo(dayWidth.value / ZOOM_STEP);
|
|
236
|
+
/** Two fingers on the timeline zoom it, as a held Ctrl and the wheel do. */
|
|
237
|
+
let pinch = null;
|
|
238
|
+
/** Starts a pinch when two fingers rest on the timeline; `true` when one began. */
|
|
239
|
+
function pinchStart(event) {
|
|
240
|
+
const el = o.chart.value;
|
|
241
|
+
if (event.touches.length !== 2 || !el) return false;
|
|
242
|
+
const { a, b, distance } = fingers(event);
|
|
243
|
+
if (!el.contains(a.target) || !el.contains(b.target)) return false;
|
|
244
|
+
pinch = {
|
|
245
|
+
distance: Math.max(1, distance),
|
|
246
|
+
dayWidth: dayWidth.value
|
|
247
|
+
};
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
/** Zooms with the fingers; `true` while a pinch is going on. */
|
|
251
|
+
function pinchMove(event) {
|
|
252
|
+
if (!pinch || event.touches.length !== 2) return false;
|
|
253
|
+
event.preventDefault();
|
|
254
|
+
const { a, b, distance } = fingers(event);
|
|
255
|
+
const rect = o.chart.value.getBoundingClientRect();
|
|
256
|
+
zoomTo(pinch.dayWidth * (distance / pinch.distance), (a.clientX + b.clientX) / 2 - rect.left);
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
function pinchEnd(event) {
|
|
260
|
+
if (event.touches.length < 2) pinch = null;
|
|
261
|
+
}
|
|
262
|
+
/** The time in view, with some room either side. */
|
|
263
|
+
const timeWindow = computed(() => ({
|
|
264
|
+
start: origin.value + (scrollLeft.value - OVERSCAN_X) / ppm.value,
|
|
265
|
+
end: origin.value + (scrollLeft.value + (o.viewWidth.value || 800) + OVERSCAN_X) / ppm.value
|
|
266
|
+
}));
|
|
267
|
+
function cells(unit, step = 1) {
|
|
268
|
+
const { start, end } = timeWindow.value;
|
|
269
|
+
return unitsBetween(unit, Math.max(start, origin.value), end, o.weekStart.value, step).map((cell) => ({
|
|
270
|
+
key: cell.start,
|
|
271
|
+
end: cell.end,
|
|
272
|
+
left: xOf(cell.start),
|
|
273
|
+
width: (cell.end - cell.start) * ppm.value,
|
|
274
|
+
label: unitLabel(unit, cell.start, o.messages.value, dayWidth.value)
|
|
275
|
+
}));
|
|
276
|
+
}
|
|
277
|
+
const headerStep = computed(() => level.value.bottom === "hour" ? hourStep(dayWidth.value) : 1);
|
|
278
|
+
const topCells = computed(() => cells(level.value.top));
|
|
279
|
+
const bottomCells = computed(() => cells(level.value.bottom, headerStep.value));
|
|
280
|
+
/** Days off, shaded; at hour level the hours outside work too. */
|
|
281
|
+
const shaded = computed(() => {
|
|
282
|
+
if (dayWidth.value < 8) return [];
|
|
283
|
+
const { start, end } = timeWindow.value;
|
|
284
|
+
return offTime(o.calendar.value, start, end, level.value.name === "hour").map((range) => ({
|
|
285
|
+
key: range.start,
|
|
286
|
+
left: xOf(range.start),
|
|
287
|
+
width: (range.end - range.start) * ppm.value
|
|
288
|
+
}));
|
|
289
|
+
});
|
|
290
|
+
const todayX = computed(() => o.today() && now.value >= extent.value.start && now.value <= extent.value.end ? xOf(now.value) : null);
|
|
291
|
+
/** A pointer's x on screen as timeline px. */
|
|
292
|
+
const contentX = (clientX) => clientX - o.chart.value.getBoundingClientRect().left + o.chart.value.scrollLeft;
|
|
293
|
+
function scrollToDate(date) {
|
|
294
|
+
const parsed = parseTime(date);
|
|
295
|
+
if (parsed) scrollToTime(parsed.at);
|
|
296
|
+
}
|
|
297
|
+
function scrollToToday() {
|
|
298
|
+
scrollToTime(now.value, o.viewWidth.value / 3);
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
dayWidth,
|
|
302
|
+
level,
|
|
303
|
+
ppm,
|
|
304
|
+
now,
|
|
305
|
+
extent,
|
|
306
|
+
origin,
|
|
307
|
+
totalWidth,
|
|
308
|
+
xOf,
|
|
309
|
+
contentX,
|
|
310
|
+
scrollTop,
|
|
311
|
+
scrollLeft,
|
|
312
|
+
scrollbar,
|
|
313
|
+
measureScrollbar,
|
|
314
|
+
onChartScroll,
|
|
315
|
+
onTableScroll,
|
|
316
|
+
scrollToTime,
|
|
317
|
+
scrollToDate,
|
|
318
|
+
scrollToToday,
|
|
319
|
+
fit,
|
|
320
|
+
fitWhenSized,
|
|
321
|
+
zoomTo,
|
|
322
|
+
zoomIn,
|
|
323
|
+
zoomOut,
|
|
324
|
+
onWheel,
|
|
325
|
+
pinchStart,
|
|
326
|
+
pinchMove,
|
|
327
|
+
pinchEnd,
|
|
328
|
+
timeWindow,
|
|
329
|
+
topCells,
|
|
330
|
+
bottomCells,
|
|
331
|
+
shaded,
|
|
332
|
+
todayX
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
export { useTimeAxis };
|
|
336
|
+
|
|
337
|
+
//# sourceMappingURL=time-axis.js.map
|