@bagelink/vue 1.2.56 → 1.2.61

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,44 @@
1
+ import { Ref, ComputedRef } from 'vue';
2
+ /**
3
+ * Clears HTML tags from a string
4
+ * @param html - HTML string to clean
5
+ * @returns Plain text without HTML tags
6
+ */
7
+ export declare function clearHtml(value?: string): string;
8
+ /**
9
+ * Normalizes text by removing special characters and converting to lowercase
10
+ * @param text - Text to normalize
11
+ * @returns Normalized text
12
+ */
13
+ export declare function normalizeText(text: string): string;
14
+ export interface SearchItemParams<T> {
15
+ searchTerm?: string | Ref<string>;
16
+ items?: T[] | Ref<T[]>;
17
+ keysToSearch?: (keyof T extends string ? keyof T : string)[];
18
+ fieldWeights?: Record<string, number>;
19
+ minChars?: number;
20
+ serverSearch?: (query: string) => Promise<T[]>;
21
+ debounceMs?: number;
22
+ }
23
+ export interface SearchResult<T> {
24
+ results: ComputedRef<readonly T[]>;
25
+ resultCount: ComputedRef<number>;
26
+ hasResults: ComputedRef<boolean>;
27
+ isSearching: ComputedRef<boolean>;
28
+ isLoading: ComputedRef<boolean>;
29
+ }
30
+ /**
31
+ * Generic search function that searches for a term within specified object properties
32
+ * If keysToSearch is not provided, searches all keys (including nested ones)
33
+ * @param params - Search parameters including searchTerm, items, keys and weights
34
+ * @returns Filtered and sorted array of items that match the search terms
35
+ */
36
+ export declare function searchItems<T>(params: SearchItemParams<T>): T[];
37
+ /**
38
+ * Vue composable for searching items with reactive results
39
+ * Supports both client-side filtering and server-side search
40
+ * @param params Search parameters
41
+ * @returns Reactive search results and metadata
42
+ */
43
+ export declare function useSearch<T>(params: SearchItemParams<T>): SearchResult<T>;
44
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/utils/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,KAAK,CAAA;AAG3C;;;;GAIG;AAEH,wBAAgB,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,UAUvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGlD;AA2ED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;IACjC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAA;IACtB,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,CAAA;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAA;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,YAAY,CAAC,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;IAClC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAChC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAChC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IACjC,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;CAC/B;AAkCD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAsK/D;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAC1B,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GACzB,YAAY,CAAC,CAAC,CAAC,CAwEjB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "1.2.56",
4
+ "version": "1.2.61",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Neveh Allon",
@@ -51,7 +51,7 @@
51
51
  "./vite.config.ts"
52
52
  ],
53
53
  "devDependencies": {
54
- "type-fest": "^4.39.1",
54
+ "type-fest": "^4",
55
55
  "@types/leaflet": "^1.9.17",
56
56
  "@types/signature_pad": "^4.0.0",
57
57
  "@vue-macros/reactivity-transform": "^1.1.6",
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@bagelink/sdk": "*",
63
- "type-fest": "^4.39.1",
63
+ "type-fest": "^4",
64
64
  "@vuepic/vue-datepicker": "^8.8.1",
65
65
  "vue": "*",
66
66
  "vue-draggable-next": "^2.2.1",
@@ -10,7 +10,7 @@ withDefaults(defineProps<{
10
10
  </script>
11
11
 
12
12
  <template>
13
- <div class="avatar flex justify-content-center" :style="{ width: `${size}px`, height: `${size}px` }">
13
+ <div class="round overflow-hidden txt-center p-0 avatar flex justify-content-center" :style="{ width: `${size}px`, height: `${size}px` }">
14
14
  <img v-if="src" :src="src" :alt="name">
15
15
  <p v-else :style="{ 'line-height': `${size}px`, 'font-size': `calc(1.5rem * ${size} / 50)` }">
16
16
  {{ (fallback || initials(name || '')).toUpperCase() }}
@@ -20,12 +20,8 @@ withDefaults(defineProps<{
20
20
 
21
21
  <style scoped>
22
22
  .avatar {
23
- border-radius: 100%;
24
23
  background-color: var(--bgl-gray-20);
25
24
  border: 0.5px solid var(--border-color);
26
- overflow: hidden;
27
- text-align: center;
28
- padding: 0;
29
25
  flex-shrink: 0;
30
26
  }
31
27
 
@@ -13,6 +13,7 @@ const props = defineProps<{
13
13
  flat?: boolean
14
14
  disabled?: boolean
15
15
  lead?: string
16
+ end?: string
16
17
  iconEnd?: IconType
17
18
  target?: '_blank' | '_self'
18
19
  thin?: boolean
@@ -77,8 +78,9 @@ const bind = $computed(() => {
77
78
  </p>
78
79
  </div>
79
80
  <div class="flex-grow-1" />
80
- <slot name="action">
81
+ <slot name="end">
81
82
  <Icon v-if="iconEnd" :icon="iconEnd" class="transition-400" />
83
+ <p v-if="end" class="txt12 m-0 p-0 opacity-7 ellipsis-1" v-text="end" />
82
84
  </slot>
83
85
  </component>
84
86
  </template>
@@ -122,7 +122,7 @@ function useCalendarView() {
122
122
 
123
123
  const years = computed(() => {
124
124
  const startYear = currentMonthValue.value.year - 10
125
- return Array.from({ length: 21 }, (_, i) => ({
125
+ return Array.from({ length: 18 }, (_, i) => ({
126
126
  value: startYear + i,
127
127
  disabled: isYearDisabled(startYear + i)
128
128
  }))
@@ -273,7 +273,7 @@ function selectDate(date: Date | null) {
273
273
  </script>
274
274
 
275
275
  <template>
276
- <div class="ltr flex gap-075 p-05 m_flex-wrap calendar-container justify-content-center h-100p">
276
+ <div class="ltr flex gap-075 m_flex-wrap calendar-container justify-content-center h-100p">
277
277
  <div class="calendar-section m_border-none pe-05 m_p-0">
278
278
  <div class="flex space-between pb-1">
279
279
  <template v-if="currentView === 'days'">
@@ -396,7 +396,7 @@ function selectDate(date: Date | null) {
396
396
 
397
397
  .year-grid {
398
398
  grid-template-columns: repeat(3, 1fr);
399
- grid-template-rows: repeat(7, 1fr);
399
+ grid-template-rows: repeat(6, 1fr);
400
400
  }
401
401
 
402
402
  .month-item,
@@ -7,10 +7,10 @@ import {
7
7
  Skeleton,
8
8
  Dropdown,
9
9
  Icon,
10
-
11
- TextInput
10
+ TextInput,
11
+ useSearch
12
12
  } from '@bagelink/vue'
13
- import { onMounted, watch } from 'vue'
13
+ import { onMounted, ref, watch } from 'vue'
14
14
  import 'floating-vue/style.css'
15
15
 
16
16
  interface PropTypes {
@@ -44,7 +44,7 @@ const searchInput = $ref<HTMLElement | undefined>()
44
44
  let selectedItems = $ref<Option[]>([])
45
45
 
46
46
  const selectedItemCount = $computed(() => selectedItems.length ?? 0)
47
- const search = $ref<string>('')
47
+ const searchTerm = ref<string>('')
48
48
 
49
49
  const dropdown = $ref<InstanceType<typeof Dropdown> | undefined>()
50
50
  let selected = $ref(false)
@@ -63,35 +63,7 @@ const selectedLabel = $computed((): string => {
63
63
  })
64
64
  const searchPlaceholder = $computed(() => props.searchPlaceholder ?? selectedLabel ?? 'Search')
65
65
 
66
- let serverOptions: Option[] = $ref([])
67
- let isSearching = $ref(false)
68
-
69
- async function runServerSearch() {
70
- if (props.onSearch !== undefined) {
71
- isSearching = true
72
- serverOptions = await props.onSearch(search)
73
- isSearching = false
74
- }
75
- }
76
-
77
- const filteredOptions = $computed(() => {
78
- if (props.onSearch !== undefined) {
79
- if (isSearching) return []
80
- if (search.trim().length) return serverOptions
81
- return props.options
82
- }
83
- return props.options.filter((option) => {
84
- const searchTerm = search
85
- .split(/\s+/)
86
- .filter(Boolean)
87
- .map(t => new RegExp(t.replaceAll(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi'))
88
- return (
89
- Boolean(option)
90
- && (searchTerm.every(s => getLabel(option).match(s))
91
- )
92
- )
93
- })
94
- })
66
+ const { results, isLoading } = useSearch<Option>({ searchTerm, serverSearch: props.onSearch, items: props.options })
95
67
 
96
68
  let highlightedIndex = $ref(-1)
97
69
 
@@ -104,9 +76,9 @@ function navigate(direction: 'up' | 'down') {
104
76
  return
105
77
  }
106
78
  if (direction === 'up') {
107
- highlightedIndex = highlightedIndex > 0 ? highlightedIndex - 1 : filteredOptions.length - 1
79
+ highlightedIndex = highlightedIndex > 0 ? highlightedIndex - 1 : results.value.length - 1
108
80
  } else if (direction === 'down') {
109
- highlightedIndex = highlightedIndex < filteredOptions.length - 1 ? highlightedIndex + 1 : 0
81
+ highlightedIndex = highlightedIndex < results.value.length - 1 ? highlightedIndex + 1 : 0
110
82
  }
111
83
  setTimeout(() => {
112
84
  const el = selectOptions?.children[highlightedIndex] as HTMLElement
@@ -246,11 +218,10 @@ onMounted(() => {
246
218
  <TextInput
247
219
  v-if="searchable && open"
248
220
  ref="searchInput"
249
- v-model="search"
221
+ v-model="searchTerm"
250
222
  class="mb-0"
251
223
  :placeholder="searchPlaceholder"
252
224
  icon="search"
253
- @debounce="runServerSearch"
254
225
  @input="selected = false"
255
226
  @click="focusInput"
256
227
  @keydown.down.prevent="navigate('down')"
@@ -295,7 +266,7 @@ onMounted(() => {
295
266
  </div>
296
267
  </label>
297
268
  </template>
298
- <Skeleton v-if="isSearching" :count="6" width="200px" height="25px" class="mx-1 my-1" />
269
+ <Skeleton v-if="isLoading" :count="6" width="200px" height="25px" class="mx-1 my-1" />
299
270
  <Card
300
271
  class="p-05"
301
272
  :style="{ width: fullWidth ? '100%' : 'auto' }"
@@ -303,7 +274,7 @@ onMounted(() => {
303
274
  >
304
275
  <div ref="selectOptions" class="selectinput-options" :class="{ multiselect }">
305
276
  <div
306
- v-for="(option, i) in filteredOptions"
277
+ v-for="(option, i) in results"
307
278
  :key="`${option}${i}`"
308
279
  class="selectinput-option hover gap-1 align-items-center"
309
280
  :class="{ selected: isSelected(option) }"
package/src/index.ts CHANGED
@@ -17,3 +17,4 @@ export * from './utils/calendar/dateUtils'
17
17
  import './styles/bagel.css'
18
18
 
19
19
  export * from './utils/constants'
20
+ export * from './utils/search'