react-schedule-picker 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/SchedulePicker.tsx","../src/constants.ts","../src/utils.ts","../src/locales.ts","../src/serialize.ts"],"sourcesContent":["// Design Ref: §4 Component Integration — locale-support\nimport { useCallback, useRef, useState, useMemo } from \"react\";\nimport type { SchedulePickerProps } from \"./types\";\nimport {\n hasHour,\n toggleHourWithMax,\n applyRect,\n formatHourHeader,\n generateSlots,\n isSlotDisabled,\n} from \"./utils\";\nimport { resolveLocaleConfig, rotateDays, getDefaultPresets } from \"./locales\";\nimport type { Schedule, Preset } from \"./types\";\nimport \"./SchedulePicker.css\";\n\nexport function SchedulePicker({\n value,\n onChange,\n onSelectEnd,\n presets: presetsProp,\n hideToolbar = false,\n readOnly = false,\n disabled = false,\n minHour = 0,\n maxHour = 23,\n visibleDays: visibleDaysProp,\n dayLabels: dayLabelsProp,\n dayAxis = \"x\",\n compactHourLabels = false,\n formatHour,\n disabledSlots,\n className,\n // Localization props\n locale,\n messages,\n weekStartsOn,\n weekendHighlight,\n}: SchedulePickerProps) {\n // Design §4.1: locale 해석 (props > preset > fallback)\n const resolvedLocale = useMemo(\n () => resolveLocaleConfig({ locale, messages, weekStartsOn, weekendHighlight }),\n [locale, messages, weekStartsOn, weekendHighlight],\n );\n\n // Design §4.1: 기존 props가 있으면 최우선, 없으면 locale 기본값\n const dayLabels = dayLabelsProp ?? resolvedLocale.dayLabels;\n const effectiveFormatHour = formatHour ?? resolvedLocale.formatHour;\n const visibleDays = useMemo(\n () => visibleDaysProp ?? rotateDays(resolvedLocale.weekStartsOn),\n [visibleDaysProp, resolvedLocale.weekStartsOn],\n );\n const activePresets = useMemo(\n () => presetsProp ?? getDefaultPresets(resolvedLocale.messages),\n [presetsProp, resolvedLocale.messages],\n );\n const [isDragging, setIsDragging] = useState(false);\n const [isHeaderDragging, setIsHeaderDragging] = useState<\"day\" | \"hour\" | false>(false);\n const [hoveredDay, setHoveredDay] = useState<string | null>(null);\n const [hoveredHour, setHoveredHour] = useState<number | null>(null);\n const [cornerHovered, setCornerHovered] = useState(false);\n const dragSelectRef = useRef(true);\n const headerDragSelectRef = useRef(true);\n const headerStartRef = useRef<number>(0);\n const baseRef = useRef<Schedule>(value);\n const startRef = useRef({ dayIdx: 0, slotIdx: 0 });\n const headerBaseRef = useRef<Schedule>(value);\n const tableRef = useRef<HTMLTableElement>(null);\n\n const slots = useMemo(\n () => generateSlots(minHour, maxHour, 1),\n [minHour, maxHour],\n );\n const getHourLabel = useCallback(\n (slot: number): string => {\n // Priority: formatHour prop > locale formatHour > formatHourHeader fallback\n // v1.0.0 호환: locale 미지정 시 effectiveFormatHour=format24h=String(h)로 동일 결과\n if (formatHour) return formatHour(slot);\n if (compactHourLabels) return formatHourHeader(slot);\n return effectiveFormatHour(slot);\n },\n [formatHour, effectiveFormatHour, compactHourLabels],\n );\n\n // --- 드래그 핸들러 ---\n\n const handleCellPointerDown = useCallback(\n (day: string, slot: number) => {\n if (readOnly || isSlotDisabled(disabledSlots, day, slot)) return;\n const dayIdx = visibleDays.indexOf(day);\n const slotIdx = slots.indexOf(slot);\n const willSelect = !hasHour(value, day, slot);\n dragSelectRef.current = willSelect;\n baseRef.current = value;\n startRef.current = { dayIdx, slotIdx };\n setIsDragging(true);\n navigator.vibrate?.(8);\n onChange(toggleHourWithMax(value, day, slot, willSelect, undefined, disabledSlots));\n },\n [value, onChange, visibleDays, slots, readOnly, disabledSlots],\n );\n\n const handleCellPointerOver = useCallback(\n (day: string, slot: number) => {\n if (!isDragging || readOnly) return;\n const dayIdx = visibleDays.indexOf(day);\n const slotIdx = slots.indexOf(slot);\n const { dayIdx: sd, slotIdx: ss } = startRef.current;\n\n const next = applyRect(baseRef.current, visibleDays, sd, slots[ss], dayIdx, slot, dragSelectRef.current, slots, undefined, disabledSlots);\n onChange(next);\n },\n [isDragging, onChange, visibleDays, slots, readOnly, disabledSlots],\n );\n\n const handlePointerUp = useCallback(() => {\n if (isDragging || isHeaderDragging) {\n onSelectEnd?.(value);\n }\n setIsDragging(false);\n setIsHeaderDragging(false);\n }, [isDragging, isHeaderDragging, onSelectEnd, value]);\n\n // --- 헤더 범위 적용 헬퍼 ---\n\n const applyDayRange = useCallback(\n (base: Schedule, startIdx: number, endIdx: number, selected: boolean): Schedule => {\n const minIdx = Math.min(startIdx, endIdx);\n const maxIdx = Math.max(startIdx, endIdx);\n let next = { ...base };\n for (let i = minIdx; i <= maxIdx; i++) {\n const day = visibleDays[i];\n if (selected) {\n const enabledSlots = slots.filter((s) => !isSlotDisabled(disabledSlots, day, s));\n next = { ...next, [day]: enabledSlots };\n } else {\n next = { ...next, [day]: [] };\n }\n }\n return next;\n },\n [visibleDays, slots, disabledSlots],\n );\n\n const applyHourRange = useCallback(\n (base: Schedule, startIdx: number, endIdx: number, selected: boolean): Schedule => {\n const minIdx = Math.min(startIdx, endIdx);\n const maxIdx = Math.max(startIdx, endIdx);\n let next = { ...base };\n for (let i = minIdx; i <= maxIdx; i++) {\n const slot = slots[i];\n for (const d of visibleDays) {\n next = toggleHourWithMax(next, d, slot, selected, undefined, disabledSlots);\n }\n }\n return next;\n },\n [visibleDays, slots, disabledSlots],\n );\n\n // --- 행/열 토글 ---\n\n const handleDayHeaderDown = useCallback(\n (day: string) => {\n if (readOnly) return;\n const dayIdx = visibleDays.indexOf(day);\n const current = value[day] ?? [];\n const enabledSlots = slots.filter((s) => !isSlotDisabled(disabledSlots, day, s));\n const allSelected = enabledSlots.length > 0 && enabledSlots.every((s) => current.includes(s));\n const willSelect = !allSelected;\n headerDragSelectRef.current = willSelect;\n headerStartRef.current = dayIdx;\n headerBaseRef.current = value;\n setIsHeaderDragging(\"day\");\n navigator.vibrate?.(8);\n onChange(applyDayRange(value, dayIdx, dayIdx, willSelect));\n },\n [value, onChange, slots, visibleDays, readOnly, disabledSlots, applyDayRange],\n );\n\n const handleDayHeaderOver = useCallback(\n (day: string) => {\n if (isHeaderDragging !== \"day\" || readOnly) return;\n const dayIdx = visibleDays.indexOf(day);\n onChange(applyDayRange(headerBaseRef.current, headerStartRef.current, dayIdx, headerDragSelectRef.current));\n },\n [isHeaderDragging, readOnly, visibleDays, onChange, applyDayRange],\n );\n\n const handleHourHeaderDown = useCallback(\n (slot: number) => {\n if (readOnly) return;\n const slotIdx = slots.indexOf(slot);\n const allSelected = visibleDays.every((d) => isSlotDisabled(disabledSlots, d, slot) || hasHour(value, d, slot));\n const willSelect = !allSelected;\n headerDragSelectRef.current = willSelect;\n headerStartRef.current = slotIdx;\n headerBaseRef.current = value;\n setIsHeaderDragging(\"hour\");\n navigator.vibrate?.(8);\n onChange(applyHourRange(value, slotIdx, slotIdx, willSelect));\n },\n [value, onChange, slots, visibleDays, readOnly, disabledSlots, applyHourRange],\n );\n\n const handleHourHeaderOver = useCallback(\n (slot: number) => {\n if (isHeaderDragging !== \"hour\" || readOnly) return;\n const slotIdx = slots.indexOf(slot);\n onChange(applyHourRange(headerBaseRef.current, headerStartRef.current, slotIdx, headerDragSelectRef.current));\n },\n [isHeaderDragging, readOnly, slots, onChange, applyHourRange],\n );\n\n // --- 터치 드래그 (셀 + 헤더) ---\n\n const handleTouchMove = useCallback(\n (e: React.TouchEvent) => {\n if ((!isDragging && !isHeaderDragging) || readOnly) return;\n e.preventDefault();\n\n const touch = e.touches[0];\n const element = document.elementFromPoint(\n touch.clientX,\n touch.clientY,\n ) as HTMLElement | null;\n if (!element) return;\n\n if (isDragging) {\n const day = element.dataset.day;\n const hourStr = element.dataset.hour;\n if (day && hourStr) {\n handleCellPointerOver(day, Number(hourStr));\n }\n return;\n }\n\n if (isHeaderDragging === \"day\") {\n const dayHeader = element.dataset.dayHeader;\n if (dayHeader) {\n handleDayHeaderOver(dayHeader);\n }\n return;\n }\n\n if (isHeaderDragging === \"hour\") {\n const hourHeader = element.dataset.hourHeader;\n if (hourHeader) {\n handleHourHeaderOver(Number(hourHeader));\n }\n }\n },\n [\n isDragging,\n isHeaderDragging,\n readOnly,\n handleCellPointerOver,\n handleDayHeaderOver,\n handleHourHeaderOver,\n ],\n );\n\n // --- 전체 토글 ---\n\n const handleToggleAll = useCallback(() => {\n if (readOnly) return;\n const allSelected = visibleDays.every((day) => {\n const enabledSlots = slots.filter((s) => !isSlotDisabled(disabledSlots, day, s));\n const current = value[day] ?? [];\n return enabledSlots.length > 0 && enabledSlots.every((s) => current.includes(s));\n });\n if (allSelected) {\n onChange({});\n } else {\n const next: Schedule = {};\n for (const day of visibleDays) {\n next[day] = slots.filter((s) => !isSlotDisabled(disabledSlots, day, s));\n }\n onChange(next);\n }\n }, [value, onChange, visibleDays, slots, readOnly, disabledSlots]);\n\n // --- 프리셋 ---\n\n const handlePreset = useCallback(\n (preset: Preset) => {\n if (readOnly) return;\n const next: Schedule = {};\n for (const d of preset.days) {\n next[d] = [...preset.hours].filter((h) => !isSlotDisabled(disabledSlots, d, h)).sort((a, b) => a - b);\n }\n onChange(next);\n },\n [onChange, readOnly, disabledSlots],\n );\n\n // --- 요일 라벨 modifier ---\n\n const getDayLabelClass = (day: string) => {\n const classes = [\"rsp-day-label\"];\n // weekendHighlight에 색상이 지정된 요일에는 모두 `rsp-day-label--{day}` 클래스 부여\n // (사용자가 CSS로 추가 스타일링 가능하도록)\n if (resolvedLocale.weekendHighlight[day]) {\n classes.push(`rsp-day-label--${day}`);\n }\n if (readOnly) classes.push(\"rsp-day-label--readonly\");\n return classes.join(\" \");\n };\n\n // Design §4.2: 주말 강조 인라인 style (locale/props 기반)\n const getDayLabelStyle = (day: string): React.CSSProperties | undefined => {\n const color = resolvedLocale.weekendHighlight[day];\n return color ? { color } : undefined;\n };\n\n // --- 셀 클래스 ---\n\n const getCellClass = (day: string, slot: number) => {\n const selected = hasHour(value, day, slot);\n const slotDisabled = isSlotDisabled(disabledSlots, day, slot);\n const highlighted = cornerHovered || hoveredDay === day || hoveredHour === slot;\n return [\n \"rsp-cell\",\n selected && \"rsp-cell--selected\",\n slotDisabled && \"rsp-cell--disabled\",\n highlighted && !selected && !slotDisabled && \"rsp-cell--highlighted\",\n readOnly && \"rsp-cell--readonly\",\n ]\n .filter(Boolean)\n .join(\" \");\n };\n\n return (\n <div\n className={`rsp-container${disabled ? \" rsp-container--disabled\" : \"\"}${className ? ` ${className}` : \"\"}`}\n onMouseUp={handlePointerUp}\n onMouseLeave={handlePointerUp}\n onTouchEnd={handlePointerUp}\n >\n {/* 프리셋 툴바 */}\n {!hideToolbar && (\n <div className=\"rsp-toolbar\">\n {activePresets.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className=\"rsp-preset-button\"\n onClick={() => handlePreset(preset)}\n disabled={readOnly}\n >\n {preset.label}\n </button>\n ))}\n <button\n type=\"button\"\n className=\"rsp-preset-button rsp-toolbar-clear\"\n onClick={() => onChange({})}\n disabled={readOnly}\n >\n {resolvedLocale.messages.clear}\n </button>\n </div>\n )}\n\n {/* 테이블 */}\n <div\n className=\"rsp-table-wrapper\"\n onTouchMove={handleTouchMove}\n >\n <table className=\"rsp-table\" ref={tableRef}>\n {dayAxis === \"y\" ? (\n <>\n <colgroup>\n <col className=\"rsp-day-col\" />\n {slots.map((s) => (\n <col key={s} />\n ))}\n </colgroup>\n <thead>\n <tr className=\"rsp-header-row\" onMouseLeave={() => setHoveredHour(null)}>\n <th\n className={`rsp-corner-cell${readOnly ? \"\" : \" rsp-corner-cell--clickable\"}`}\n onClick={handleToggleAll}\n onMouseEnter={() => setCornerHovered(true)}\n onMouseLeave={() => setCornerHovered(false)}\n onTouchEnd={(e) => {\n e.preventDefault();\n handleToggleAll();\n }}\n />\n {slots.map((s) => (\n <th\n key={s}\n data-hour-header={s}\n className={`rsp-header-cell${readOnly ? \" rsp-header-cell--readonly\" : \"\"}`}\n onMouseDown={(e) => {\n e.preventDefault();\n handleHourHeaderDown(s);\n }}\n onMouseOver={() => {\n setHoveredHour(s);\n handleHourHeaderOver(s);\n }}\n onMouseEnter={() => setHoveredHour(s)}\n onTouchStart={(e) => {\n e.preventDefault();\n handleHourHeaderDown(s);\n }}\n >\n <span>{getHourLabel(s)}</span>\n </th>\n ))}\n </tr>\n </thead>\n <tbody onMouseLeave={() => setHoveredDay(null)}>\n {visibleDays.map((day) => (\n <tr key={day} className=\"rsp-day-row\">\n <td\n data-day-header={day}\n className={getDayLabelClass(day)}\n style={getDayLabelStyle(day)}\n onMouseDown={(e) => {\n e.preventDefault();\n handleDayHeaderDown(day);\n }}\n onMouseOver={() => {\n setHoveredDay(day);\n handleDayHeaderOver(day);\n }}\n onMouseEnter={() => setHoveredDay(day)}\n onMouseLeave={() => setHoveredDay(null)}\n onTouchStart={(e) => {\n e.preventDefault();\n handleDayHeaderDown(day);\n }}\n >\n {dayLabels[day] ?? day}\n </td>\n {slots.map((slot) => (\n <td\n key={slot}\n className={getCellClass(day, slot)}\n data-day={day}\n data-hour={slot}\n onMouseDown={(e) => {\n e.preventDefault();\n handleCellPointerDown(day, slot);\n }}\n onMouseOver={() => handleCellPointerOver(day, slot)}\n onTouchStart={(e) => {\n e.preventDefault();\n handleCellPointerDown(day, slot);\n }}\n >\n\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </>\n ) : (\n <>\n <colgroup>\n <col className=\"rsp-hour-col\" />\n {visibleDays.map((d) => (\n <col key={d} />\n ))}\n </colgroup>\n <thead>\n <tr className=\"rsp-header-row\" onMouseLeave={() => setHoveredDay(null)}>\n <th\n className={`rsp-corner-cell${readOnly ? \"\" : \" rsp-corner-cell--clickable\"}`}\n onClick={handleToggleAll}\n onMouseEnter={() => setCornerHovered(true)}\n onMouseLeave={() => setCornerHovered(false)}\n onTouchEnd={(e) => {\n e.preventDefault();\n handleToggleAll();\n }}\n />\n {visibleDays.map((day) => (\n <th\n key={day}\n data-day-header={day}\n className={`rsp-header-cell rsp-header-cell--day${readOnly ? \" rsp-header-cell--readonly\" : \"\"}`}\n style={getDayLabelStyle(day)}\n onMouseDown={(e) => {\n e.preventDefault();\n handleDayHeaderDown(day);\n }}\n onMouseOver={() => {\n setHoveredDay(day);\n handleDayHeaderOver(day);\n }}\n onMouseEnter={() => setHoveredDay(day)}\n onTouchStart={(e) => {\n e.preventDefault();\n handleDayHeaderDown(day);\n }}\n >\n <span>{dayLabels[day] ?? day}</span>\n </th>\n ))}\n </tr>\n </thead>\n <tbody onMouseLeave={() => setHoveredHour(null)}>\n {slots.map((slot) => (\n <tr key={slot} className=\"rsp-day-row\">\n <td\n data-hour-header={slot}\n className={`rsp-hour-label${readOnly ? \" rsp-hour-label--readonly\" : \"\"}`}\n onMouseDown={(e) => {\n e.preventDefault();\n handleHourHeaderDown(slot);\n }}\n onMouseOver={() => {\n setHoveredHour(slot);\n handleHourHeaderOver(slot);\n }}\n onMouseEnter={() => setHoveredHour(slot)}\n onMouseLeave={() => setHoveredHour(null)}\n onTouchStart={(e) => {\n e.preventDefault();\n handleHourHeaderDown(slot);\n }}\n >\n {getHourLabel(slot)}\n </td>\n {visibleDays.map((day) => (\n <td\n key={day}\n className={getCellClass(day, slot)}\n data-day={day}\n data-hour={slot}\n onMouseDown={(e) => {\n e.preventDefault();\n handleCellPointerDown(day, slot);\n }}\n onMouseOver={() => handleCellPointerOver(day, slot)}\n onTouchStart={(e) => {\n e.preventDefault();\n handleCellPointerDown(day, slot);\n }}\n >\n\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </>\n )}\n </table>\n </div>\n </div>\n );\n}\n","import type { Preset } from \"./types\";\n\n/** 요일 표시 순서: 월~일 */\nexport const DAY_ORDER = [\"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\", \"sun\"] as const;\n\n/** 기본 요일 라벨 (영어) */\nexport const DAY_LABELS: Record<string, string> = {\n mon: \"Mon\",\n tue: \"Tue\",\n wed: \"Wed\",\n thu: \"Thu\",\n fri: \"Fri\",\n sat: \"Sat\",\n sun: \"Sun\",\n};\n\n/** 0~23 시간 배열 */\nexport const HOURS = Array.from({ length: 24 }, (_, i) => i);\n\nconst WEEKDAYS = [\"mon\", \"tue\", \"wed\", \"thu\", \"fri\"];\nconst WEEKENDS = [\"sat\", \"sun\"];\nconst DAY_HOURS = [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];\nconst NIGHT_HOURS = [18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5];\n\n/**\n * 내장 프리셋 4종 (영어 라벨 고정).\n * @deprecated v1.1+ — 로케일 기반 번역된 프리셋을 얻으려면 `getDefaultPresets(messages)`\n * 또는 `<SchedulePicker locale=\"...\" />`를 사용하세요. 이 상수는 하위호환 목적으로만 유지됩니다.\n */\nexport const DEFAULT_PRESETS: Preset[] = [\n { label: \"Weekday Day\", days: WEEKDAYS, hours: DAY_HOURS },\n { label: \"Weekday Night\", days: WEEKDAYS, hours: NIGHT_HOURS },\n { label: \"Weekend Day\", days: WEEKENDS, hours: DAY_HOURS },\n { label: \"Weekend Night\", days: WEEKENDS, hours: NIGHT_HOURS },\n];\n","import type { Schedule } from \"./types\";\nimport { DAY_ORDER, HOURS } from \"./constants\";\n\n/** hourlyChunks에 따른 슬롯 배열 생성 */\nexport function generateSlots(\n minHour: number,\n maxHour: number,\n hourlyChunks: number,\n): number[] {\n const slots: number[] = [];\n const step = 1 / hourlyChunks;\n for (let h = minHour; h <= maxHour; h++) {\n for (let c = 0; c < hourlyChunks; c++) {\n slots.push(h + c * step);\n }\n }\n return slots;\n}\n\n/** 슬롯 값을 시간 문자열로 변환 (예: 9.5 → \"9:30\") */\nexport function slotToTimeString(slot: number): string {\n const hour = Math.floor(slot);\n const minutes = Math.round((slot - hour) * 60);\n return `${hour}:${String(minutes).padStart(2, \"0\")}`;\n}\n\n/** 특정 요일-슬롯이 선택되었는지 확인 */\nexport function hasHour(\n schedule: Schedule,\n day: string,\n hour: number,\n): boolean {\n return schedule[day]?.includes(hour) ?? false;\n}\n\n/** 특정 요일-슬롯이 disabled인지 확인 */\nexport function isSlotDisabled(\n disabledSlots: Schedule | undefined,\n day: string,\n hour: number,\n): boolean {\n if (!disabledSlots) return false;\n return disabledSlots[day]?.includes(hour) ?? false;\n}\n\n/** 특정 요일-슬롯을 선택/해제한 새 Schedule 반환 */\nexport function toggleHour(\n schedule: Schedule,\n day: string,\n hour: number,\n selected: boolean,\n): Schedule {\n const current = schedule[day] ?? [];\n const next = selected\n ? [...new Set([...current, hour])].sort((a, b) => a - b)\n : current.filter((h) => h !== hour);\n return { ...schedule, [day]: next };\n}\n\n/** maxSelections를 고려하여 토글 */\nexport function toggleHourWithMax(\n schedule: Schedule,\n day: string,\n hour: number,\n selected: boolean,\n maxSelections: number | undefined,\n disabledSlots: Schedule | undefined,\n): Schedule {\n if (isSlotDisabled(disabledSlots, day, hour)) return schedule;\n if (selected && maxSelections !== undefined) {\n const currentCount = countSelectedHours(schedule);\n if (currentCount >= maxSelections) return schedule;\n }\n return toggleHour(schedule, day, hour, selected);\n}\n\n/** 시작점~끝점 사각형 영역을 일괄 선택/해제한 새 Schedule 반환 */\nexport function applyRect(\n base: Schedule,\n visibleDays: readonly string[],\n startDayIdx: number,\n startHour: number,\n endDayIdx: number,\n endHour: number,\n selected: boolean,\n slots: number[],\n maxSelections?: number,\n disabledSlots?: Schedule,\n): Schedule {\n const minDayIdx = Math.min(startDayIdx, endDayIdx);\n const maxDayIdx = Math.max(startDayIdx, endDayIdx);\n const startSlotIdx = slots.indexOf(startHour);\n const endSlotIdx = slots.indexOf(endHour);\n const minSlotIdx = Math.min(startSlotIdx, endSlotIdx);\n const maxSlotIdx = Math.max(startSlotIdx, endSlotIdx);\n\n let next = { ...base };\n for (let di = minDayIdx; di <= maxDayIdx; di++) {\n const day = visibleDays[di];\n for (let si = minSlotIdx; si <= maxSlotIdx; si++) {\n next = toggleHourWithMax(next, day, slots[si], selected, maxSelections, disabledSlots);\n }\n }\n return next;\n}\n\n/** 시작점~끝점을 시간순(linear)으로 연속 선택/해제 */\nexport function applyLinear(\n base: Schedule,\n visibleDays: readonly string[],\n startDayIdx: number,\n startSlotIdx: number,\n endDayIdx: number,\n endSlotIdx: number,\n selected: boolean,\n slots: number[],\n maxSelections?: number,\n disabledSlots?: Schedule,\n): Schedule {\n const totalSlots = slots.length;\n const startPos = startDayIdx * totalSlots + startSlotIdx;\n const endPos = endDayIdx * totalSlots + endSlotIdx;\n const minPos = Math.min(startPos, endPos);\n const maxPos = Math.max(startPos, endPos);\n\n let next = { ...base };\n for (let pos = minPos; pos <= maxPos; pos++) {\n const di = Math.floor(pos / totalSlots);\n const si = pos % totalSlots;\n if (di < visibleDays.length && si < slots.length) {\n next = toggleHourWithMax(next, visibleDays[di], slots[si], selected, maxSelections, disabledSlots);\n }\n }\n return next;\n}\n\n/** 시간 헤더 포맷: 3의 배수는 숫자, 나머지는 \"·\" */\nexport function formatHourHeader(hour: number): string {\n if (Number.isInteger(hour) && hour % 3 === 0) return String(hour);\n return \"\\u00B7\";\n}\n\n/** 선택된 총 슬롯 수 계산 */\nexport function countSelectedHours(schedule: Schedule): number {\n return Object.values(schedule).reduce(\n (sum, hours) => sum + (hours?.length ?? 0),\n 0,\n );\n}\n\n/** 모든 시간이 선택되었는지 확인 */\nexport function isAllSelected(\n schedule: Schedule,\n visibleDays: readonly string[] = DAY_ORDER,\n): boolean {\n return visibleDays.every((day) => (schedule[day]?.length ?? 0) === 24);\n}\n\n/** 선택된 스케줄을 사람이 읽기 쉬운 요약 문자열로 변환 */\nexport function summarizeSchedule(\n schedule: Schedule,\n dayLabels: Record<string, string> = {\n mon: \"Mon\", tue: \"Tue\", wed: \"Wed\", thu: \"Thu\",\n fri: \"Fri\", sat: \"Sat\", sun: \"Sun\",\n },\n visibleDays: readonly string[] = DAY_ORDER,\n hourlyChunks: number = 1,\n noSelectionLabel: string = \"No selection\",\n): string {\n const step = 1 / hourlyChunks;\n const entries = visibleDays\n .filter((day) => (schedule[day]?.length ?? 0) > 0)\n .map((day) => {\n const slots = [...(schedule[day] ?? [])].sort((a, b) => a - b);\n const ranges: string[] = [];\n let start = slots[0];\n let prev = slots[0];\n for (let i = 1; i <= slots.length; i++) {\n if (i < slots.length && Math.abs(slots[i] - prev - step) < 0.001) {\n prev = slots[i];\n } else {\n const endTime = prev + step;\n ranges.push(`${slotToTimeString(start)}-${slotToTimeString(endTime)}`);\n start = slots[i];\n prev = slots[i];\n }\n }\n return `${dayLabels[day] ?? day}: ${ranges.join(\", \")}`;\n });\n return entries.length > 0 ? entries.join(\" | \") : noSelectionLabel;\n}\n\n/** 빈 Schedule 생성 */\nexport function createEmptySchedule(): Schedule {\n return {};\n}\n\n/** 모든 시간이 선택된 Schedule 생성 */\nexport function createFullSchedule(\n visibleDays: readonly string[] = DAY_ORDER,\n): Schedule {\n const schedule: Schedule = {};\n for (const day of visibleDays) {\n schedule[day] = [...HOURS];\n }\n return schedule;\n}\n","// Design Ref: §2 Type Design, §3 Data Model — locale-support\n// Plan SC: SC1 (locale 한 줄 적용), SC2 (en-US), SC4 (v1 호환)\nimport type { Preset } from \"./types\";\nimport { DAY_ORDER } from \"./constants\";\n\n// === Types ===\n\nexport type LocaleKey = \"en\" | \"en-US\" | \"ko\" | \"ja\" | \"zh-CN\" | \"zh-TW\";\n\nexport type WeekStartsOn = \"mon\" | \"sun\" | \"sat\";\n\nexport interface Messages {\n clear: string;\n noSelection: string;\n presets: {\n weekdayDay: string;\n weekdayNight: string;\n weekendDay: string;\n weekendNight: string;\n };\n}\n\n/** 요일별 CSS color. \"none\" = 강조 없음 */\nexport type WeekendHighlight = Record<string, string> | \"none\";\n\nexport interface LocalePreset {\n messages: Messages;\n weekStartsOn: WeekStartsOn;\n weekendHighlight: WeekendHighlight;\n formatHour: (hour: number) => string;\n dayLabels: Record<string, string>;\n}\n\n/** resolveLocaleConfig 결과 — 컴포넌트가 실제 사용하는 값 */\nexport interface ResolvedLocaleConfig {\n messages: Messages;\n weekStartsOn: WeekStartsOn;\n weekendHighlight: Record<string, string>; // \"none\"은 {}로 정규화\n formatHour: (hour: number) => string;\n dayLabels: Record<string, string>;\n}\n\n// === Format helpers ===\n\nconst format24h = (h: number): string => String(h);\n\nconst format12hAmPm = (h: number): string => {\n if (h === 0) return \"12AM\";\n if (h === 12) return \"12PM\";\n if (h < 12) return String(h);\n return String(h - 12);\n};\n\n// === Label data ===\n\nconst PRESET_LABELS = {\n en: {\n weekdayDay: \"Weekday Day\",\n weekdayNight: \"Weekday Night\",\n weekendDay: \"Weekend Day\",\n weekendNight: \"Weekend Night\",\n },\n ko: {\n weekdayDay: \"평일 주간\",\n weekdayNight: \"평일 야간\",\n weekendDay: \"주말 주간\",\n weekendNight: \"주말 야간\",\n },\n ja: {\n weekdayDay: \"平日 日中\",\n weekdayNight: \"平日 夜間\",\n weekendDay: \"週末 日中\",\n weekendNight: \"週末 夜間\",\n },\n zhCN: {\n weekdayDay: \"工作日白天\",\n weekdayNight: \"工作日夜间\",\n weekendDay: \"周末白天\",\n weekendNight: \"周末夜间\",\n },\n zhTW: {\n weekdayDay: \"工作日白天\",\n weekdayNight: \"工作日夜間\",\n weekendDay: \"週末白天\",\n weekendNight: \"週末夜間\",\n },\n} as const;\n\nconst DAY_LABELS_BY_LOCALE = {\n en: { mon: \"Mon\", tue: \"Tue\", wed: \"Wed\", thu: \"Thu\", fri: \"Fri\", sat: \"Sat\", sun: \"Sun\" },\n ko: { mon: \"월\", tue: \"화\", wed: \"수\", thu: \"목\", fri: \"금\", sat: \"토\", sun: \"일\" },\n ja: { mon: \"月\", tue: \"火\", wed: \"水\", thu: \"木\", fri: \"金\", sat: \"土\", sun: \"日\" },\n zhCN: { mon: \"周一\", tue: \"周二\", wed: \"周三\", thu: \"周四\", fri: \"周五\", sat: \"周六\", sun: \"周日\" },\n zhTW: { mon: \"週一\", tue: \"週二\", wed: \"週三\", thu: \"週四\", fri: \"週五\", sat: \"週六\", sun: \"週日\" },\n} as const;\n\n// === LOCALE_PRESETS ===\n// 문화적 컨벤션 기반 주말 색상:\n// - en, en-US: 서양 캘린더는 주말 색상 구분 없음\n// - ko, ja: 토 파랑, 일 빨강 (전통 컨벤션)\n// - zh-CN, zh-TW: 토일 모두 빨강\n\nexport const LOCALE_PRESETS: Record<LocaleKey, LocalePreset> = {\n \"en\": {\n messages: {\n clear: \"Clear\",\n noSelection: \"No selection\",\n presets: PRESET_LABELS.en,\n },\n weekStartsOn: \"mon\",\n weekendHighlight: \"none\",\n formatHour: format24h,\n dayLabels: DAY_LABELS_BY_LOCALE.en,\n },\n \"en-US\": {\n messages: {\n clear: \"Clear\",\n noSelection: \"No selection\",\n presets: PRESET_LABELS.en,\n },\n weekStartsOn: \"sun\",\n weekendHighlight: \"none\",\n formatHour: format12hAmPm,\n dayLabels: DAY_LABELS_BY_LOCALE.en,\n },\n \"ko\": {\n messages: {\n clear: \"초기화\",\n noSelection: \"선택 없음\",\n presets: PRESET_LABELS.ko,\n },\n weekStartsOn: \"mon\",\n weekendHighlight: { sat: \"#2d6af6\", sun: \"#f04646\" },\n formatHour: format24h,\n dayLabels: DAY_LABELS_BY_LOCALE.ko,\n },\n \"ja\": {\n messages: {\n clear: \"クリア\",\n noSelection: \"未選択\",\n presets: PRESET_LABELS.ja,\n },\n weekStartsOn: \"sun\",\n weekendHighlight: { sat: \"#2d6af6\", sun: \"#f04646\" },\n formatHour: format24h,\n dayLabels: DAY_LABELS_BY_LOCALE.ja,\n },\n \"zh-CN\": {\n messages: {\n clear: \"清除\",\n noSelection: \"未选择\",\n presets: PRESET_LABELS.zhCN,\n },\n weekStartsOn: \"mon\",\n weekendHighlight: { sat: \"#f04646\", sun: \"#f04646\" },\n formatHour: format24h,\n dayLabels: DAY_LABELS_BY_LOCALE.zhCN,\n },\n \"zh-TW\": {\n messages: {\n clear: \"清除\",\n noSelection: \"未選擇\",\n presets: PRESET_LABELS.zhTW,\n },\n weekStartsOn: \"mon\",\n weekendHighlight: { sat: \"#f04646\", sun: \"#f04646\" },\n formatHour: format24h,\n dayLabels: DAY_LABELS_BY_LOCALE.zhTW,\n },\n};\n\n// === resolveLocaleConfig ===\n// Design §3.2: 우선순위 props > preset > fallback\n\nexport interface ResolveLocaleInput {\n locale?: LocaleKey;\n messages?: Partial<Messages>;\n weekStartsOn?: WeekStartsOn;\n weekendHighlight?: WeekendHighlight;\n}\n\nexport function resolveLocaleConfig(input: ResolveLocaleInput = {}): ResolvedLocaleConfig {\n const preset = LOCALE_PRESETS[input.locale ?? \"en\"] ?? LOCALE_PRESETS.en;\n\n const mergedMessages: Messages = {\n clear: input.messages?.clear ?? preset.messages.clear,\n noSelection: input.messages?.noSelection ?? preset.messages.noSelection,\n presets: {\n ...preset.messages.presets,\n ...input.messages?.presets,\n },\n };\n\n const rawHighlight = input.weekendHighlight ?? preset.weekendHighlight;\n const normalizedHighlight: Record<string, string> =\n rawHighlight === \"none\" ? {} : rawHighlight;\n\n return {\n messages: mergedMessages,\n weekStartsOn: input.weekStartsOn ?? preset.weekStartsOn,\n weekendHighlight: normalizedHighlight,\n formatHour: preset.formatHour,\n dayLabels: preset.dayLabels,\n };\n}\n\n// === rotateDays ===\n// Design §4.1: visibleDays 기본값을 weekStartsOn 기준으로 회전\n\nexport function rotateDays(weekStartsOn: WeekStartsOn): string[] {\n const base = [...DAY_ORDER];\n const startIdx = base.indexOf(weekStartsOn);\n if (startIdx <= 0) return base;\n return [...base.slice(startIdx), ...base.slice(0, startIdx)];\n}\n\n// === getDefaultPresets ===\n// Design §11.1 M1: 프리셋을 messages에서 번역된 라벨로 생성\n\nconst WEEKDAYS = [\"mon\", \"tue\", \"wed\", \"thu\", \"fri\"];\nconst WEEKENDS = [\"sat\", \"sun\"];\nconst DAY_HOURS = [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];\nconst NIGHT_HOURS = [18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5];\n\nexport function getDefaultPresets(messages: Messages): Preset[] {\n return [\n { label: messages.presets.weekdayDay, days: WEEKDAYS, hours: DAY_HOURS },\n { label: messages.presets.weekdayNight, days: WEEKDAYS, hours: NIGHT_HOURS },\n { label: messages.presets.weekendDay, days: WEEKENDS, hours: DAY_HOURS },\n { label: messages.presets.weekendNight, days: WEEKENDS, hours: NIGHT_HOURS },\n ];\n}\n","import type { Schedule } from \"./types\";\nimport { DAY_ORDER } from \"./constants\";\n\n/** ISO 8601 요일 번호 (1=월 ... 7=일) */\nexport type IsoDayOfWeek = 1 | 2 | 3 | 4 | 5 | 6 | 7;\n\n/** 요일 키 ↔ ISO 요일 번호 매핑 */\nconst DAY_TO_ISO: Record<string, IsoDayOfWeek> = {\n mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6, sun: 7,\n};\nconst ISO_TO_DAY: Record<IsoDayOfWeek, string> = {\n 1: \"mon\", 2: \"tue\", 3: \"wed\", 4: \"thu\", 5: \"fri\", 6: \"sat\", 7: \"sun\",\n};\n\n/** 단일 시간 구간 (반-개방 구간: [start, end)) */\nexport interface TimeRange {\n /** ISO 요일 번호 (1=월 ... 7=일) */\n day: IsoDayOfWeek;\n /** 시작 시각 \"HH:mm\" (포함) */\n start: string;\n /** 종료 시각 \"HH:mm\" (제외). 24:00이면 자정 직전까지 */\n end: string;\n}\n\n/** 구간 기반 직렬화 결과 */\nexport interface RangesPayload {\n version: 1;\n /** IANA 타임존 (예: \"Asia/Seoul\"). 없으면 생략 */\n timezone?: string;\n /** 선택된 구간들 */\n ranges: TimeRange[];\n /** 사용자 정의 메타데이터 */\n meta?: Record<string, unknown>;\n}\n\n/** toRanges 옵션 */\nexport interface ToRangesOptions {\n timezone?: string;\n meta?: Record<string, unknown>;\n}\n\nfunction pad2(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\nfunction hourToTimeString(hour: number): string {\n return `${pad2(hour)}:00`;\n}\n\n/** 연속된 hour 배열을 [start, endExclusive) 구간들로 압축 */\nfunction compressHours(hours: number[]): Array<{ start: number; end: number }> {\n if (hours.length === 0) return [];\n const sorted = [...hours].sort((a, b) => a - b);\n const out: Array<{ start: number; end: number }> = [];\n let start = sorted[0];\n let prev = sorted[0];\n for (let i = 1; i < sorted.length; i++) {\n const cur = sorted[i];\n if (cur === prev + 1) {\n prev = cur;\n } else {\n out.push({ start, end: prev + 1 });\n start = cur;\n prev = cur;\n }\n }\n out.push({ start, end: prev + 1 });\n return out;\n}\n\n/**\n * Schedule을 구간 기반 포맷으로 변환합니다.\n * - 연속된 시간은 하나의 구간으로 압축됩니다 (예: [9,10,11] → 09:00~12:00).\n * - 요일 키는 ISO 8601 번호(1=월~7=일)로 변환되어 정렬됩니다.\n * - 타임존/메타데이터를 함께 담을 수 있습니다.\n */\nexport function toRanges(\n schedule: Schedule,\n options: ToRangesOptions = {},\n): RangesPayload {\n const ranges: TimeRange[] = [];\n for (const dayKey of DAY_ORDER) {\n const iso = DAY_TO_ISO[dayKey];\n if (!iso) continue;\n const hours = schedule[dayKey];\n if (!hours || hours.length === 0) continue;\n for (const { start, end } of compressHours(hours)) {\n ranges.push({\n day: iso,\n start: hourToTimeString(start),\n end: end >= 24 ? \"24:00\" : hourToTimeString(end),\n });\n }\n }\n\n const payload: RangesPayload = { version: 1, ranges };\n if (options.timezone) payload.timezone = options.timezone;\n if (options.meta) payload.meta = options.meta;\n return payload;\n}\n\n/** \"HH:mm\" → hour. 분 단위는 무시되지만, 1시간 단위가 아니면 에러 */\nfunction parseTimeString(s: string): number {\n const m = /^(\\d{1,2}):(\\d{2})$/.exec(s);\n if (!m) throw new Error(`Invalid time string: ${s}`);\n const h = Number(m[1]);\n const min = Number(m[2]);\n if (min !== 0) {\n throw new Error(\n `fromRanges only supports hour-aligned times (got ${s}). ` +\n `Sub-hour granularity is not supported in current version.`,\n );\n }\n if (h < 0 || h > 24) throw new Error(`Hour out of range: ${h}`);\n return h;\n}\n\n/**\n * 구간 기반 포맷을 Schedule로 역변환합니다.\n * - 1시간 정렬되지 않은 구간(예: 09:30)은 에러를 던집니다.\n * - \"24:00\"은 자정으로 해석됩니다.\n */\nexport function fromRanges(payload: RangesPayload): Schedule {\n const schedule: Schedule = {};\n for (const range of payload.ranges) {\n const dayKey = ISO_TO_DAY[range.day];\n if (!dayKey) throw new Error(`Invalid ISO day: ${range.day}`);\n const start = parseTimeString(range.start);\n const end = parseTimeString(range.end);\n if (end <= start) {\n throw new Error(\n `Range end (${range.end}) must be after start (${range.start})`,\n );\n }\n const hours = schedule[dayKey] ?? [];\n for (let h = start; h < end; h++) {\n if (!hours.includes(h)) hours.push(h);\n }\n hours.sort((a, b) => a - b);\n schedule[dayKey] = hours;\n }\n return schedule;\n}\n\n/** toISO 옵션 */\nexport interface ToISOOptions {\n timezone?: string;\n meta?: Record<string, unknown>;\n}\n\n/**\n * Schedule을 ISO 8601 호환 문자열 배열로 직렬화합니다.\n * - 각 항목은 `{day, startTime, endTime, timezone?}` 형태로, 캘린더 시스템에\n * 전달하기 쉬운 형태입니다. (iCalendar BYDAY 규약과 유사)\n * - 주의: 이 출력은 \"주간 반복 가용시간\"의 표현이며, 특정 날짜가 아닙니다.\n */\nexport function toISO(\n schedule: Schedule,\n options: ToISOOptions = {},\n): {\n version: 1;\n timezone?: string;\n availability: Array<{\n day: IsoDayOfWeek;\n startTime: string;\n endTime: string;\n }>;\n meta?: Record<string, unknown>;\n} {\n const payload = toRanges(schedule, options);\n const availability = payload.ranges.map((r) => ({\n day: r.day,\n startTime: r.start,\n endTime: r.end,\n }));\n const out: ReturnType<typeof toISO> = { version: 1, availability };\n if (options.timezone) out.timezone = options.timezone;\n if (options.meta) out.meta = options.meta;\n return out;\n}\n"],"mappings":"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","names":["WEEKDAYS","WEEKENDS","DAY_HOURS","NIGHT_HOURS"]}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "react-schedule-picker",
3
+ "version": "1.0.0",
4
+ "description": "Drag-to-select weekly schedule picker for React. Zero dependencies, fully typed, locale-aware.",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./styles.css": "./dist/index.css"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "sideEffects": [
22
+ "*.css"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "dev": "tsup --watch",
27
+ "demo": "vite example",
28
+ "build:demo": "vite build example",
29
+ "typecheck": "tsc --noEmit",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "peerDependencies": {
33
+ "react": ">=18",
34
+ "react-dom": ">=18"
35
+ },
36
+ "devDependencies": {
37
+ "@types/react": "^18.0.0",
38
+ "@types/react-dom": "^18.0.0",
39
+ "@vitejs/plugin-react": "^6.0.1",
40
+ "react": "^18.0.0",
41
+ "react-dom": "^18.0.0",
42
+ "tsup": "^8.0.0",
43
+ "typescript": "^5.0.0",
44
+ "vite": "^8.0.8"
45
+ },
46
+ "keywords": [
47
+ "react",
48
+ "schedule",
49
+ "picker",
50
+ "weekly",
51
+ "time-slot",
52
+ "grid",
53
+ "drag-select",
54
+ "availability",
55
+ "calendar",
56
+ "timetable"
57
+ ],
58
+ "author": "innerbloo",
59
+ "license": "MIT",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/innerbloo/react-schedule-picker.git"
63
+ },
64
+ "bugs": {
65
+ "url": "https://github.com/innerbloo/react-schedule-picker/issues"
66
+ },
67
+ "homepage": "https://react-schedule-picker.vercel.app/"
68
+ }