Skip to content

Instantly share code, notes, and snippets.

View manabuyasuda's full-sized avatar

安田 学 manabuyasuda

View GitHub Profile
@manabuyasuda
manabuyasuda / .svgrrc.js
Created May 13, 2025 09:23
SVGファイルをSVGRでコンポーネント化して共通Iconコンポーネントで管理する
module.exports = {
typescript: true, // .tsxファイルを生成する
memo: true, // Reactのメモ化を有効にする
jsxRuntime: 'automatic', // Reactの明示的なインポートをしない
filenameCase: 'kebab', // ファイル名をkebab-caseにする
index: false, // index.tsxファイルを生成しない
svgoConfig: {
plugins: [
{
name: 'preset-default', // 標準的なプリセットを使用する
/**
* w記述子で生成する画像サイズパターン
* https://nextjs.org/docs/pages/api-reference/components/image#advanced
*/
export const srcSetSizes = [16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1010];
/**
* 画像の初期設定値
*/
export const DEFAULT_IMAGE_QUALITY = 90;
import { usePathname, useSearchParams } from 'next/navigation';
import { useCallback, useEffect, useRef, useMemo } from 'react';
type ScrollIntoViewOptions = {
behavior?: ScrollBehavior;
block?: ScrollLogicalPosition;
inline?: ScrollLogicalPosition;
};
interface UseLinkScrollOptions {
import { useEffect, useCallback, useRef } from 'react';
// ブラウザ環境かどうかを判定する
const isBrowser = typeof window !== 'undefined';
// iOSデバイスかどうかを判定する
const isIosDevice =
isBrowser &&
window.navigator &&
window.navigator.platform &&
import { useEffect, useCallback, useRef, useState } from 'react';
/**
* 開閉処理以外のオプション設定。
*/
type ModalOptions = {
/** Escキーでモーダルを閉じるかどうか @default true */
closeOnEsc?: boolean;
/** フォーカストラップを有効にするかどうか @default true */
enableFocusTrap?: boolean;
// 任意の引数を受け取る関数型
type AnyFunction = (...args: any[]) => any;
// スロットル制御された関数の型
type ThrottledFunction<T extends AnyFunction> = {
(...args: Parameters<T>): void;
cancel: () => void;
};
/**
/**
* メディアクエリの一致状態を監視するカスタムフックです。
* @param mediaQuery メディアクエリ文字列(例: '(min-width: 768px)')
* @returns boolean - メディアクエリに一致する場合はtrue、それ以外はfalse
*/
export function useMediaQuery(mediaQuery: string): boolean {
// サーバーサイドでは初期値を`false`として、クライアントサイドでは結果を返す
const getInitialValue = () =>
typeof window !== 'undefined'
? window.matchMedia(mediaQuery).matches
/**
* 特定のスクロール位置(要素)を通過したかどうかを監視するカスタムフックです。
* スクロール位置と要素の位置を比較して、要素を通過したかどうかを判定します。
* @param {string} selector 監視対象の要素を特定するCSSセレクタ
* @param {Object} options 監視オプション
* @param {string} options.scrollBasePosition スクロール量の基準位置を画面の上端('top')または下端('bottom')とするか
* @param {string} options.elementBasePosition 要素の基準位置を要素の上端('top')または下端('bottom')とするか
* @param {boolean} options.once 一度要素を通過したら監視を終了するかどうか
* @returns {boolean} true: スクロール量が要素の位置を超えた, false: まだ要素の位置まで到達していない
*/
/**
* 指定秒数の間スクロールが止まっているかを監視するカスタムフックです。
* スクロールイベントとタイマーを組み合わせて、ユーザーのスクロール停止状態を検知します。
* @param {number} timeoutSeconds スクロールが止まったと判定するまでの秒数(デフォルト: 3秒)
* @returns {boolean} スクロールの状態
* - true: 一定時間スクロールが止まっている(指定秒数の間にスクロールなし)
* - false: スクロールが発生している(直近の指定秒数以内にスクロールあり)
*/
export function useScrollStopped(timeoutSeconds: number = 3): boolean {
// 一定時間スクロールが止まっているかどうか
/**
* スクロール方向
* 'up': ページトップ方向へのスクロール(ページを上に戻る)
* 'down': ページボトム方向へのスクロール(ページを下に進める)
* 'none': スクロールが発生していない状態
*/
type VerticalScrollDirection = 'up' | 'down' | 'none';
/**
* スクロール方向を監視するhook