{"version":3,"file":"JFilterBar.vue2.cjs","sources":["../../../../src/components/organisms/JFilterBar.vue"],"sourcesContent":["<template>\n  <div :class=\"cn('j-filter-bar w-full rounded-sm border bg-card text-card-foreground shadow-sm', props.class)\">\n    <!-- Row 1: toolbar -->\n    <div class=\"flex items-center justify-between px-2 py-1\">\n      <div class=\"flex items-center gap-1\">\n        <button\n          v-if=\"collapsible\"\n          type=\"button\"\n          class=\"flex items-center justify-center h-6 w-6 rounded hover:bg-accent hover:text-accent-foreground transition-colors\"\n          @click=\"toggleCollapsed\"\n        >\n          <ChevronDown\n            :class=\"[\n              'h-3.5 w-3.5 transition-transform',\n              isExpanded ? 'rotate-0' : '-rotate-90',\n            ]\"\n          />\n        </button>\n        <!-- 타이틀 -->\n        <JLabel\n          v-if=\"title\"\n          :text=\"title\"\n          class=\"text-sm font-semibold text-foreground\"\n        />\n        <!-- 선택된 필터 뱃지 표시 -->\n        <div v-if=\"activeFilters.length > 0\" class=\"flex items-center gap-1 flex-wrap\">\n          <JBadge\n            v-for=\"filter in activeFilters\"\n            :key=\"filter.key\"\n            variant=\"secondary\"\n            size=\"sm\"\n            class=\"flex items-center gap-1 cursor-default\"\n          >\n            <span class=\"text-muted-foreground\">{{ filter.label }}:</span>\n            <span>{{ filter.value }}</span>\n            <button\n              type=\"button\"\n              class=\"ml-0.5 rounded-full hover:bg-gray-300 p-0.5 transition-colors\"\n              @click.stop=\"removeFilter(filter.key)\"\n            >\n              <X class=\"h-3 w-3\" />\n            </button>\n          </JBadge>\n        </div>\n      </div>\n      <div class=\"flex items-center gap-1\">\n        <slot name=\"actions\" />\n        <JButton\n          v-if=\"showResetButton\"\n          variant=\"secondary\"\n          size=\"sm\"\n          @click=\"handleReset\"\n        >\n          {{ resetButtonText }}\n        </JButton>\n        <JButton\n          v-if=\"showSearchButton\"\n          styletype=\"primary\"\n          size=\"sm\"\n          @click=\"handleSearch\"\n        >\n          {{ searchButtonText }}\n        </JButton>\n      </div>\n    </div>\n\n    <!-- Row 2: filters (반응형 그리드: max 4열, 자동 축소) -->\n    <div v-show=\"isExpanded\" class=\"px-2 pb-2\">\n      <div class=\"filter-fields-grid\">\n        <slot name=\"filters\" />\n      </div>\n    </div>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { ChevronDown, X } from 'lucide-vue-next'\nimport JBadge from '@/components/atoms/JBadge.vue'\nimport JButton from '@/components/atoms/JButton.vue'\nimport JLabel from '@/components/atoms/JLabel.vue'\nimport { cn } from '@/lib/utils'\n\n/** 활성 필터 아이템 타입 */\nexport interface ActiveFilterItem {\n  /** 필터 식별 키 */\n  key: string\n  /** 표시할 라벨 (필터명) */\n  label: string\n  /** 표시할 값 */\n  value: string\n}\n\n/** 필터 설정 타입 */\nexport interface FilterDisplayItem {\n  /** 표시할 라벨 */\n  label: string\n  /** 값을 표시용 문자열로 변환 (예: combo value -> label) */\n  displayValue?: (value: unknown) => string\n}\n\nexport interface JFilterBarProps {\n  /** 추가 클래스 (외부 커스터마이징용) */\n  class?: string\n  /** 필터바 타이틀 */\n  title?: string\n  /** 필터 접힘 상태 (v-model 지원) */\n  collapsed?: boolean\n  /** 접기/펼치기 가능 여부. false면 토글 버튼 숨김 & 필터 항상 표시 */\n  collapsible?: boolean\n  /** 필터 값 객체 (v-model:filterValues 지원) */\n  filterValues?: Record<string, unknown>\n  /** 필터 표시 설정 (label, displayValue 등) */\n  filterDisplay?: Record<string, FilterDisplayItem>\n  /** 초기화 버튼 표시 여부 */\n  showResetButton?: boolean\n  /** 조회 버튼 표시 여부 */\n  showSearchButton?: boolean\n  /** 초기화 버튼 텍스트 */\n  resetButtonText?: string\n  /** 조회 버튼 텍스트 */\n  searchButtonText?: string\n}\n\nconst props = withDefaults(defineProps<JFilterBarProps>(), {\n  collapsed: true,\n  collapsible: true,\n  filterValues: () => ({}),\n  filterDisplay: () => ({}),\n  showResetButton: false,\n  showSearchButton: false,\n  resetButtonText: '초기화',\n  searchButtonText: '조회',\n})\n\nconst emit = defineEmits<{\n  'update:collapsed': [value: boolean]\n  'update:filterValues': [value: Record<string, unknown>]\n  /** 조회 버튼 클릭 */\n  search: []\n  /** 초기화 버튼 클릭 */\n  reset: []\n}>()\n\nconst isExpanded = computed(() => {\n  if (!props.collapsible) return true\n  return !props.collapsed\n})\n\n/** 값이 비어있는지 확인 */\nfunction isEmpty(value: unknown): boolean {\n  if (value === null || value === undefined) return true\n  if (typeof value === 'string' && value.trim() === '') return true\n  if (Array.isArray(value) && value.length === 0) return true\n  return false\n}\n\n/** filterValues + filterDisplay 기반으로 활성 필터 목록 자동 생성 */\nconst activeFilters = computed<ActiveFilterItem[]>(() => {\n  const filters: ActiveFilterItem[] = []\n\n  for (const [key, config] of Object.entries(props.filterDisplay)) {\n    const value = props.filterValues[key]\n    if (isEmpty(value)) continue\n\n    const displayValue = config.displayValue ? config.displayValue(value) : String(value)\n    if (displayValue.trim() === '') continue\n\n    filters.push({\n      key,\n      label: config.label,\n      value: displayValue,\n    })\n  }\n\n  return filters\n})\n\nfunction toggleCollapsed() {\n  emit('update:collapsed', !props.collapsed)\n}\n\nfunction handleReset() {\n  // filterValues의 모든 값을 초기화\n  const resetValues: Record<string, unknown> = {}\n  for (const key of Object.keys(props.filterValues)) {\n    const currentValue = props.filterValues[key]\n    if (typeof currentValue === 'string') {\n      resetValues[key] = ''\n    } else if (Array.isArray(currentValue)) {\n      resetValues[key] = []\n    } else {\n      resetValues[key] = null\n    }\n  }\n  emit('update:filterValues', resetValues)\n  emit('reset')\n}\n\nfunction handleSearch() {\n  emit('search')\n}\n\nfunction removeFilter(key: string) {\n  // filterValues 업데이트 (해당 키 값을 초기화)\n  const newValues = { ...props.filterValues }\n  const currentValue = newValues[key]\n\n  // 타입에 따라 적절한 초기값으로 설정\n  if (typeof currentValue === 'string') {\n    newValues[key] = ''\n  } else if (Array.isArray(currentValue)) {\n    newValues[key] = []\n  } else {\n    newValues[key] = null\n  }\n\n  emit('update:filterValues', newValues)\n}\n</script>\n\n<style scoped>\n/* 활성 필터 배지 — cursor-default(JBadge)의 기본 상태 구분감 보정 */\n:deep(.cursor-default) {\n  background-color: hsl(var(--muted) / 0.82) !important;\n  border: 1px solid hsl(var(--border) / 0.9) !important;\n}\n:deep(.cursor-default) > button {\n  background-color: hsl(var(--background) / 0.98);\n  color: hsl(var(--foreground) / 0.9);\n}\n:deep(.cursor-default) > button:hover {\n  background-color: hsl(var(--muted) / 1);\n  color: hsl(var(--foreground));\n}\n\n/* 필터 필드 반응형 그리드: max 4열, 자동 축소 (4 → 3 → 2 → 1) */\n.filter-fields-grid {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(max(25% - 0.75rem, 220px), 1fr));\n  gap: 0.375rem 0.75rem;\n  --label-w: 5rem; /* 필터 컨텍스트: 라벨 컴팩트 (80px) → 필드에 공간 확보 */\n}\n\n/* ========================================\n   패턴 3: Tabs 아래 배치 시 연결 스타일\n   ======================================== */\n\n:deep([data-state=\"active\"]) > .j-filter-bar {\n  border-top: none;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n\n:deep([role=\"tabpanel\"]) .j-filter-bar {\n  border-top: none;\n}\n</style>\n"],"names":["props","__props","emit","__emit","isExpanded","computed","isEmpty","value","activeFilters","filters","key","config","displayValue","toggleCollapsed","handleReset","resetValues","currentValue","handleSearch","removeFilter","newValues","_createElementBlock","_normalizeClass","_unref","cn","_createElementVNode","_hoisted_1","_hoisted_2","_createVNode","ChevronDown","_createBlock","JLabel","_openBlock","_hoisted_3","_Fragment","_renderList","filter","JBadge","_hoisted_4","_toDisplayString","_withModifiers","$event","X","_hoisted_6","_renderSlot","_ctx","JButton","_withDirectives","_hoisted_7","_hoisted_8"],"mappings":"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"}