nexa-ui-kit 0.6.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.
Files changed (114) hide show
  1. package/dist/NBadge.nexa +40 -0
  2. package/dist/NBottomSheet.nexa +124 -0
  3. package/dist/NButton.nexa +123 -0
  4. package/dist/NCard.nexa +74 -0
  5. package/dist/NInput.nexa +116 -0
  6. package/dist/NModal.nexa +165 -0
  7. package/dist/NSelect.nexa +169 -0
  8. package/dist/NToastContainer.nexa +86 -0
  9. package/dist/NTooltip.nexa +115 -0
  10. package/dist/components/NAlert.js +134 -0
  11. package/dist/components/NAlert.nexa +115 -0
  12. package/dist/components/NAutocomplete.js +94 -0
  13. package/dist/components/NAutocomplete.nexa +58 -0
  14. package/dist/components/NAvatar.js +75 -0
  15. package/dist/components/NAvatar.nexa +67 -0
  16. package/dist/components/NBadge.js +74 -0
  17. package/dist/components/NBadge.nexa +61 -0
  18. package/dist/components/NBottomSheet.js +149 -0
  19. package/dist/components/NBottomSheet.nexa +145 -0
  20. package/dist/components/NButton.js +284 -0
  21. package/dist/components/NButton.nexa +275 -0
  22. package/dist/components/NCard.js +117 -0
  23. package/dist/components/NCard.nexa +100 -0
  24. package/dist/components/NCheckbox.js +108 -0
  25. package/dist/components/NCheckbox.nexa +90 -0
  26. package/dist/components/NChips.js +72 -0
  27. package/dist/components/NChips.nexa +57 -0
  28. package/dist/components/NDataTable.js +252 -0
  29. package/dist/components/NDataTable.nexa +186 -0
  30. package/dist/components/NDatepicker.js +379 -0
  31. package/dist/components/NDatepicker.nexa +367 -0
  32. package/dist/components/NForm.js +132 -0
  33. package/dist/components/NForm.nexa +133 -0
  34. package/dist/components/NFormField.js +173 -0
  35. package/dist/components/NFormField.nexa +171 -0
  36. package/dist/components/NInput.js +311 -0
  37. package/dist/components/NInput.nexa +311 -0
  38. package/dist/components/NInputNumber.js +202 -0
  39. package/dist/components/NInputNumber.nexa +199 -0
  40. package/dist/components/NModal.js +221 -0
  41. package/dist/components/NModal.nexa +221 -0
  42. package/dist/components/NMultiSelect.js +156 -0
  43. package/dist/components/NMultiSelect.nexa +77 -0
  44. package/dist/components/NPaginator.js +117 -0
  45. package/dist/components/NPaginator.nexa +77 -0
  46. package/dist/components/NPassword.js +193 -0
  47. package/dist/components/NPassword.nexa +178 -0
  48. package/dist/components/NProgressBar.js +127 -0
  49. package/dist/components/NProgressBar.nexa +111 -0
  50. package/dist/components/NRadio.js +96 -0
  51. package/dist/components/NRadio.nexa +81 -0
  52. package/dist/components/NSelect.js +468 -0
  53. package/dist/components/NSelect.nexa +452 -0
  54. package/dist/components/NSkeleton.js +98 -0
  55. package/dist/components/NSkeleton.nexa +74 -0
  56. package/dist/components/NSwitch.js +92 -0
  57. package/dist/components/NSwitch.nexa +76 -0
  58. package/dist/components/NTabs.js +129 -0
  59. package/dist/components/NTabs.nexa +113 -0
  60. package/dist/components/NTag.js +108 -0
  61. package/dist/components/NTag.nexa +93 -0
  62. package/dist/components/NToastContainer.js +242 -0
  63. package/dist/components/NToastContainer.nexa +221 -0
  64. package/dist/components/NTooltip.js +163 -0
  65. package/dist/components/NTooltip.nexa +166 -0
  66. package/dist/components/NTreeMenu.js +151 -0
  67. package/dist/components/NTreeMenu.nexa +142 -0
  68. package/dist/index.d.ts +32 -0
  69. package/dist/index.js +34 -0
  70. package/dist/services/FloatingOverlay.d.ts +27 -0
  71. package/dist/services/FloatingOverlay.js +98 -0
  72. package/dist/services/FormValidation.d.ts +8 -0
  73. package/dist/services/FormValidation.js +46 -0
  74. package/dist/services/ToastService.d.ts +16 -0
  75. package/dist/services/ToastService.js +26 -0
  76. package/dist/styles/theme.d.ts +1 -0
  77. package/dist/styles/theme.js +144 -0
  78. package/package.json +32 -0
  79. package/src/components/NAlert.nexa +115 -0
  80. package/src/components/NAutocomplete.nexa +58 -0
  81. package/src/components/NAvatar.nexa +67 -0
  82. package/src/components/NBadge.nexa +61 -0
  83. package/src/components/NBottomSheet.nexa +145 -0
  84. package/src/components/NButton.nexa +275 -0
  85. package/src/components/NCard.nexa +100 -0
  86. package/src/components/NCheckbox.nexa +90 -0
  87. package/src/components/NChips.nexa +57 -0
  88. package/src/components/NDataTable.nexa +186 -0
  89. package/src/components/NDatepicker.nexa +367 -0
  90. package/src/components/NForm.nexa +133 -0
  91. package/src/components/NFormField.nexa +171 -0
  92. package/src/components/NInput.nexa +311 -0
  93. package/src/components/NInputNumber.nexa +199 -0
  94. package/src/components/NModal.nexa +221 -0
  95. package/src/components/NMultiSelect.nexa +77 -0
  96. package/src/components/NPaginator.nexa +77 -0
  97. package/src/components/NPassword.nexa +178 -0
  98. package/src/components/NProgressBar.nexa +111 -0
  99. package/src/components/NRadio.nexa +81 -0
  100. package/src/components/NSelect.nexa +452 -0
  101. package/src/components/NSkeleton.nexa +74 -0
  102. package/src/components/NSwitch.nexa +76 -0
  103. package/src/components/NTabs.nexa +113 -0
  104. package/src/components/NTag.nexa +93 -0
  105. package/src/components/NToastContainer.nexa +221 -0
  106. package/src/components/NTooltip.nexa +166 -0
  107. package/src/components/NTreeMenu.nexa +142 -0
  108. package/src/index.ts +36 -0
  109. package/src/services/FloatingOverlay.ts +133 -0
  110. package/src/services/FormValidation.ts +44 -0
  111. package/src/services/ToastService.ts +41 -0
  112. package/src/shims.d.ts +5 -0
  113. package/src/styles/theme.ts +146 -0
  114. package/src/styles/tokens.css +170 -0
@@ -0,0 +1,94 @@
1
+ import { signal, computed, effect, onBeforeUnmount, h, hText, defineComponent, registerComponent, reloadComponent, injectStyle, Teleport } from 'nexa-framework'
2
+ import { trackFloatingOverlay } from '../services/FloatingOverlay.js'
3
+
4
+ const _sfc_main = defineComponent({
5
+ __scopeId: 'data-v-741257a1',
6
+ __hmrId: 'NAutocomplete_nexa',
7
+ props: { modelValue: { type: String, default: '' }, options: { type: Array, default: () => [] }, placeholder: { type: String, default: '' }, label: { type: String, default: '' }, disabled: { type: Boolean, default: false }, readonly: { type: Boolean, default: false }, clearable: { type: Boolean, default: false }, minLength: { type: Number, default: 1 }, delay: { type: Number, default: 200 }, loading: { type: Boolean, default: false }, dropdown: { type: Boolean, default: false }, emptyMessage: { type: String, default: 'No results' }, placement: { type: String, default: 'auto' } },
8
+ emits: ['update:modelValue', 'select', 'complete', 'clear'],
9
+ setup(props, setupContext) {
10
+ const { emit, slots, slots: $slots } = setupContext
11
+ const instanceId = `n-ac-${Math.random().toString(16).slice(2)}`
12
+ const listboxId = `${instanceId}-listbox`
13
+ const inputId = `${instanceId}-input`
14
+ const isOpen = signal(false)
15
+ const query = signal('')
16
+ const focusedIndex = signal(-1)
17
+ const rootEl = signal(null)
18
+ const popupStyle = signal({})
19
+ const resolvedPlacement = signal('bottom')
20
+ let stopTracking = null
21
+ let completeTimer = null
22
+ const normalizeOption = (opt) => { if (opt == null) return { label: '', value: null, raw: opt }; if (typeof opt === 'string' || typeof opt === 'number') return { label: String(opt), value: opt, raw: opt }; if (typeof opt === 'object') { const label = 'label' in opt ? String(opt.label) : String(opt.value ?? ''); return { label, value: 'value' in opt ? opt.value : label, raw: opt } } return { label: String(opt), value: opt, raw: opt } }
23
+ const normalizedOptions = computed(() => props.options.map(normalizeOption))
24
+ const filteredOptions = computed(() => { const q = query.value.trim().toLowerCase(); if (!q) return normalizedOptions.value; return normalizedOptions.value.filter(opt => opt.label.toLowerCase().includes(q)) })
25
+ const activeId = computed(() => { const idx = focusedIndex.value; if (idx < 0) return ''; const opt = filteredOptions.value[idx]; return opt ? `${instanceId}-opt-${idx}` : '' })
26
+ const close = () => { if (!isOpen.value) return; isOpen.value = false; focusedIndex.value = -1; if (stopTracking) { stopTracking(); stopTracking = null } }
27
+ const open = (e) => { if (props.disabled || props.readonly || isOpen.value) return; isOpen.value = true; const t = e?.currentTarget || e?.target; rootEl.value = t?.closest ? t.closest(`[data-autocomplete-root="${instanceId}"]`) : null; stopTracking = trackFloatingOverlay({ isOpen: () => isOpen.value, getAnchor: () => { const root = rootEl.value; return root ? root.querySelector('.n-ac-input-wrap') : null }, getPopup: () => document.querySelector(`[data-autocomplete-popup="${instanceId}"]`), placement: props.placement, align: 'start', matchWidth: true, minWidth: 240, gap: 8, margin: 8, zIndex: 9999, onUpdate: (r) => { popupStyle.value = r.style; resolvedPlacement.value = r.placement }, isEventInside: (ev) => { const el = ev.target; if (!el || typeof el.closest !== 'function') return false; return !!(el.closest(`[data-autocomplete-root="${instanceId}"]`) || el.closest(`[data-autocomplete-popup="${instanceId}"]`)) }, onOutside: () => close() }) }
28
+ const requestComplete = () => { clearTimeout(completeTimer); completeTimer = setTimeout(() => emit('complete', query.value), props.delay) }
29
+ const onInput = (e) => { const value = e.target.value; query.value = value; emit('update:modelValue', value); if (value.trim().length >= props.minLength) { open(e); requestComplete() } else close() }
30
+ const onFocus = (e) => { query.value = props.modelValue || ''; if ((props.modelValue || '').trim().length >= props.minLength) { open(e); requestComplete() } }
31
+ const onKeydown = (e) => { if (e.key === 'Escape') { e.preventDefault(); close(); return } if (!isOpen.value) { if (e.key === 'ArrowDown') { e.preventDefault(); open(e); focusedIndex.value = 0 } return } const items = filteredOptions.value; if (e.key === 'ArrowDown') { e.preventDefault(); focusedIndex.value = Math.min(focusedIndex.value + 1, items.length - 1); return } if (e.key === 'ArrowUp') { e.preventDefault(); focusedIndex.value = Math.max(focusedIndex.value - 1, 0); return } if (e.key === 'Enter') { e.preventDefault(); const opt = items[focusedIndex.value]; if (!opt) return; emit('update:modelValue', opt.label); emit('select', opt.raw); query.value = opt.label; close() } }
32
+ const selectOption = (opt) => { emit('update:modelValue', opt.label); emit('select', opt.raw); query.value = opt.label; close() }
33
+ const clearValue = () => { if (props.disabled || props.readonly) return; emit('update:modelValue', ''); emit('clear'); query.value = ''; close() }
34
+ const openAll = (e) => { if (props.disabled || props.readonly) return; query.value = props.modelValue || ''; open(e); requestComplete() }
35
+ effect(() => { if (!isOpen.value) return; if (focusedIndex.value < 0 && filteredOptions.value.length > 0) focusedIndex.value = 0 })
36
+ onBeforeUnmount(() => { clearTimeout(completeTimer); close() })
37
+ return { instanceId, listboxId, inputId, isOpen, query, focusedIndex, rootEl, popupStyle, resolvedPlacement, stopTracking, completeTimer, normalizeOption, normalizedOptions, filteredOptions, activeId, close, open, requestComplete, onInput, onFocus, onKeydown, selectOption, clearValue, openAll, onBeforeUnmount, trackFloatingOverlay, $slots, emit }
38
+ }
39
+ })
40
+ // Injected render function
41
+ _sfc_main.render = function(ctx) {
42
+ const { instanceId, listboxId, inputId, isOpen, query, focusedIndex, rootEl, popupStyle, resolvedPlacement, stopTracking, completeTimer, normalizeOption, normalizedOptions, filteredOptions, activeId, close, open, requestComplete, onInput, onFocus, onKeydown, selectOption, clearValue, openAll, onBeforeUnmount, trackFloatingOverlay, $slots, emit, modelValue, options, placeholder, label, disabled, readonly, clearable, minLength, delay, loading, dropdown, emptyMessage, placement, Fragment: _ntc_Fragment, Teleport: _ntc_Teleport } = ctx
43
+ return h('div', { class: "n-ac", "data-autocomplete-root": instanceId, "data-v-741257a1": "" }, [
44
+ "\n ",
45
+ (label) ? h('label', { class: "n-ac-label", for: inputId, "data-v-741257a1": "" }, [
46
+ label
47
+ ]) : null,
48
+ h('div', { class: ["n-ac-input-wrap", { 'is-disabled': disabled }], "data-v-741257a1": "" }, [
49
+ "\n ",
50
+ h('input', { class: "n-ac-input", id: inputId, value: modelValue, placeholder: placeholder, disabled: disabled, readonly: readonly, role: "combobox", "aria-autocomplete": "list", "aria-expanded": isOpen.value, "aria-controls": listboxId, "aria-activedescendant": activeId.value || undefined, onInput: onInput, onFocus: onFocus, onKeydown: onKeydown, "data-v-741257a1": "" }),
51
+ "\n ",
52
+ h('div', { class: "n-ac-actions", "data-v-741257a1": "" }, [
53
+ "\n ",
54
+ (clearable && modelValue) ? h('button', { class: "n-ac-action", type: "button", disabled: disabled || readonly, "aria-label": "Limpiar", onClick: clearValue, "data-v-741257a1": "" }, [
55
+ "✕"
56
+ ]) : null,
57
+ (dropdown) ? h('button', { class: "n-ac-action", type: "button", disabled: disabled || readonly, "aria-label": "Abrir", onClick: openAll, "data-v-741257a1": "" }, [
58
+ "▾"
59
+ ]) : null
60
+ ]),
61
+ "\n "
62
+ ]),
63
+ "\n ",
64
+ h(_ntc_Teleport, { to: "body", "data-v-741257a1": "" }, [
65
+ "\n ",
66
+ (isOpen.value) ? h('div', { class: ["n-ac-popup", { 'is-top': resolvedPlacement.value === 'top' }], "data-autocomplete-popup": instanceId, style: popupStyle.value, "data-v-741257a1": "" }, [
67
+ "\n ",
68
+ (loading) ? h('div', { class: "n-ac-loading", "data-v-741257a1": "" }, [
69
+ "Loading..."
70
+ ]) : (true) ? h('div', { class: "n-ac-list", role: "listbox", id: listboxId, "data-v-741257a1": "" }, [
71
+ "\n ",
72
+ filteredOptions.value.map((opt, i) =>
73
+ h('button', { class: ["n-ac-option", { 'is-focused': i === focusedIndex.value }], key: opt.value, type: "button", role: "option", id: instanceId + '-opt-' + i, "aria-selected": (i === focusedIndex.value).toString(), onMouseenter: ($event) => { focusedIndex.value = i }, onClick: ($event) => { selectOption(opt) }, "data-v-741257a1": "" }, [
74
+ opt.label
75
+ ])
76
+ ),
77
+ "\n ",
78
+ (filteredOptions.value.length === 0) ? h('div', { class: "n-ac-empty", "data-v-741257a1": "" }, [
79
+ emptyMessage
80
+ ]) : null
81
+ ]) : null,
82
+ "\n "
83
+ ]) : null
84
+ ]),
85
+ "\n "
86
+ ])
87
+ }
88
+ _sfc_main.__scopeId = 'data-v-741257a1'
89
+ _sfc_main.__hmrId = 'NAutocomplete_nexa'
90
+
91
+ export default _sfc_main
92
+
93
+ const __style = `.n-ac[data-v-741257a1]{display:flex;flex-direction:column;gap:var(--n-space-2);width:100%;font-family:var(--n-font-sans)}.n-ac-label{display:block;font-size:var(--n-text-sm);font-weight:var(--n-weight-medium);color:var(--n-color-text-secondary);margin-bottom:var(--n-space-2)}.n-ac-input-wrap{position:relative;display:flex;align-items:center;background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);transition:all var(--n-transition-fast)}.n-ac-input-wrap:focus-within{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-ac-input{width:100%;background:transparent;border:none;outline:none;padding:0.75rem 2.75rem 0.75rem 1rem;color:var(--n-color-text);font-size:var(--n-text-base);font-family:inherit}.n-ac-input::placeholder{color:var(--n-color-text-muted)}.n-ac-actions{position:absolute;right:0.5rem;display:flex;align-items:center;gap:0.15rem}.n-ac-action{background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;padding:0.25rem;border-radius:var(--n-radius-sm);transition:all var(--n-transition-fast);line-height:1;display:flex;align-items:center}.n-ac-action:hover:not(:disabled){color:var(--n-color-text);background:var(--n-color-glass)}.n-ac-action:disabled{opacity:0.5;cursor:not-allowed}.n-ac-input-wrap.is-disabled{opacity:0.5;cursor:not-allowed;background:var(--n-color-surface-alt)}.n-ac-popup{background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);box-shadow:var(--n-shadow-lg);overflow:hidden;animation:n-ac-in .2s cubic-bezier(0,1,0,1)}.n-ac-popup.is-top{animation:n-ac-in-top .2s cubic-bezier(0,1,0,1)}@keyframes n-ac-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}@keyframes n-ac-in-top{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.n-ac-loading{padding:var(--n-space-3) var(--n-space-4);color:var(--n-color-text-muted);font-size:var(--n-text-sm)}.n-ac-list{max-height:260px;overflow:auto;display:flex;flex-direction:column}.n-ac-option{text-align:left;padding:0.7rem 1rem;color:var(--n-color-text-secondary);background:transparent;border:none;cursor:pointer;transition:all var(--n-transition-fast)}.n-ac-option:hover,.n-ac-option.is-focused{background:var(--n-color-glass);color:var(--n-color-text)}.n-ac-empty{padding:var(--n-space-4);color:var(--n-color-text-muted);text-align:center;font-size:var(--n-text-sm)}`
94
+ injectStyle('data-v-741257a1', __style)
@@ -0,0 +1,58 @@
1
+ <script setup>
2
+ import { signal, computed, effect, onBeforeUnmount } from 'nexa-framework'
3
+ import { trackFloatingOverlay } from '../services/FloatingOverlay.js'
4
+ const props = defineProps({ modelValue: { type: String, default: '' }, options: { type: Array, default: () => [] }, placeholder: { type: String, default: '' }, label: { type: String, default: '' }, disabled: { type: Boolean, default: false }, readonly: { type: Boolean, default: false }, clearable: { type: Boolean, default: false }, minLength: { type: Number, default: 1 }, delay: { type: Number, default: 200 }, loading: { type: Boolean, default: false }, dropdown: { type: Boolean, default: false }, emptyMessage: { type: String, default: 'No results' }, placement: { type: String, default: 'auto' } })
5
+ const emit = defineEmits(['update:modelValue', 'select', 'complete', 'clear'])
6
+ const instanceId = `n-ac-${Math.random().toString(16).slice(2)}`
7
+ const listboxId = `${instanceId}-listbox`
8
+ const inputId = `${instanceId}-input`
9
+ const isOpen = signal(false)
10
+ const query = signal('')
11
+ const focusedIndex = signal(-1)
12
+ const rootEl = signal(null)
13
+ const popupStyle = signal({})
14
+ const resolvedPlacement = signal('bottom')
15
+ let stopTracking = null
16
+ let completeTimer = null
17
+ const normalizeOption = (opt) => { if (opt == null) return { label: '', value: null, raw: opt }; if (typeof opt === 'string' || typeof opt === 'number') return { label: String(opt), value: opt, raw: opt }; if (typeof opt === 'object') { const label = 'label' in opt ? String(opt.label) : String(opt.value ?? ''); return { label, value: 'value' in opt ? opt.value : label, raw: opt } } return { label: String(opt), value: opt, raw: opt } }
18
+ const normalizedOptions = computed(() => props.options.map(normalizeOption))
19
+ const filteredOptions = computed(() => { const q = query.value.trim().toLowerCase(); if (!q) return normalizedOptions.value; return normalizedOptions.value.filter(opt => opt.label.toLowerCase().includes(q)) })
20
+ const activeId = computed(() => { const idx = focusedIndex.value; if (idx < 0) return ''; const opt = filteredOptions.value[idx]; return opt ? `${instanceId}-opt-${idx}` : '' })
21
+ const close = () => { if (!isOpen.value) return; isOpen.value = false; focusedIndex.value = -1; if (stopTracking) { stopTracking(); stopTracking = null } }
22
+ const open = (e) => { if (props.disabled || props.readonly || isOpen.value) return; isOpen.value = true; const t = e?.currentTarget || e?.target; rootEl.value = t?.closest ? t.closest(`[data-autocomplete-root="${instanceId}"]`) : null; stopTracking = trackFloatingOverlay({ isOpen: () => isOpen.value, getAnchor: () => { const root = rootEl.value; return root ? root.querySelector('.n-ac-input-wrap') : null }, getPopup: () => document.querySelector(`[data-autocomplete-popup="${instanceId}"]`), placement: props.placement, align: 'start', matchWidth: true, minWidth: 240, gap: 8, margin: 8, zIndex: 9999, onUpdate: (r) => { popupStyle.value = r.style; resolvedPlacement.value = r.placement }, isEventInside: (ev) => { const el = ev.target; if (!el || typeof el.closest !== 'function') return false; return !!(el.closest(`[data-autocomplete-root="${instanceId}"]`) || el.closest(`[data-autocomplete-popup="${instanceId}"]`)) }, onOutside: () => close() }) }
23
+ const requestComplete = () => { clearTimeout(completeTimer); completeTimer = setTimeout(() => emit('complete', query.value), props.delay) }
24
+ const onInput = (e) => { const value = e.target.value; query.value = value; emit('update:modelValue', value); if (value.trim().length >= props.minLength) { open(e); requestComplete() } else close() }
25
+ const onFocus = (e) => { query.value = props.modelValue || ''; if ((props.modelValue || '').trim().length >= props.minLength) { open(e); requestComplete() } }
26
+ const onKeydown = (e) => { if (e.key === 'Escape') { e.preventDefault(); close(); return } if (!isOpen.value) { if (e.key === 'ArrowDown') { e.preventDefault(); open(e); focusedIndex.value = 0 } return } const items = filteredOptions.value; if (e.key === 'ArrowDown') { e.preventDefault(); focusedIndex.value = Math.min(focusedIndex.value + 1, items.length - 1); return } if (e.key === 'ArrowUp') { e.preventDefault(); focusedIndex.value = Math.max(focusedIndex.value - 1, 0); return } if (e.key === 'Enter') { e.preventDefault(); const opt = items[focusedIndex.value]; if (!opt) return; emit('update:modelValue', opt.label); emit('select', opt.raw); query.value = opt.label; close() } }
27
+ const selectOption = (opt) => { emit('update:modelValue', opt.label); emit('select', opt.raw); query.value = opt.label; close() }
28
+ const clearValue = () => { if (props.disabled || props.readonly) return; emit('update:modelValue', ''); emit('clear'); query.value = ''; close() }
29
+ const openAll = (e) => { if (props.disabled || props.readonly) return; query.value = props.modelValue || ''; open(e); requestComplete() }
30
+ effect(() => { if (!isOpen.value) return; if (focusedIndex.value < 0 && filteredOptions.value.length > 0) focusedIndex.value = 0 })
31
+ onBeforeUnmount(() => { clearTimeout(completeTimer); close() })
32
+ </script>
33
+
34
+ <template>
35
+ <div class="n-ac" :data-autocomplete-root="instanceId">
36
+ <label v-if="label" class="n-ac-label" :for="inputId">{{ label }}</label>
37
+ <div class="n-ac-input-wrap" :class="{ 'is-disabled': disabled }">
38
+ <input class="n-ac-input" :id="inputId" :value="modelValue" :placeholder="placeholder" :disabled="disabled" :readonly="readonly" role="combobox" aria-autocomplete="list" :aria-expanded="isOpen.value" :aria-controls="listboxId" :aria-activedescendant="activeId.value || undefined" @input="onInput" @focus="onFocus" @keydown="onKeydown" />
39
+ <div class="n-ac-actions">
40
+ <button v-if="clearable && modelValue" type="button" class="n-ac-action" :disabled="disabled || readonly" aria-label="Limpiar" @click="clearValue">✕</button>
41
+ <button v-if="dropdown" type="button" class="n-ac-action" :disabled="disabled || readonly" aria-label="Abrir" @click="openAll">▾</button>
42
+ </div>
43
+ </div>
44
+ <Teleport to="body">
45
+ <div v-if="isOpen.value" class="n-ac-popup" :class="{ 'is-top': resolvedPlacement.value === 'top' }" :data-autocomplete-popup="instanceId" :style="popupStyle.value">
46
+ <div v-if="loading" class="n-ac-loading">Loading...</div>
47
+ <div v-else class="n-ac-list" role="listbox" :id="listboxId">
48
+ <button v-for="(opt, i) in filteredOptions.value" :key="opt.value" type="button" class="n-ac-option" role="option" :id="instanceId + '-opt-' + i" :aria-selected="(i === focusedIndex.value).toString()" :class="{ 'is-focused': i === focusedIndex.value }" @mouseenter="focusedIndex.value = i" @click="selectOption(opt)">{{ opt.label }}</button>
49
+ <div v-if="filteredOptions.value.length === 0" class="n-ac-empty">{{ emptyMessage }}</div>
50
+ </div>
51
+ </div>
52
+ </Teleport>
53
+ </div>
54
+ </template>
55
+
56
+ <style scoped>
57
+ .n-ac{display:flex;flex-direction:column;gap:var(--n-space-2);width:100%;font-family:var(--n-font-sans)}.n-ac-label{display:block;font-size:var(--n-text-sm);font-weight:var(--n-weight-medium);color:var(--n-color-text-secondary);margin-bottom:var(--n-space-2)}.n-ac-input-wrap{position:relative;display:flex;align-items:center;background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);transition:all var(--n-transition-fast)}.n-ac-input-wrap:focus-within{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-ac-input{width:100%;background:transparent;border:none;outline:none;padding:0.75rem 2.75rem 0.75rem 1rem;color:var(--n-color-text);font-size:var(--n-text-base);font-family:inherit}.n-ac-input::placeholder{color:var(--n-color-text-muted)}.n-ac-actions{position:absolute;right:0.5rem;display:flex;align-items:center;gap:0.15rem}.n-ac-action{background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;padding:0.25rem;border-radius:var(--n-radius-sm);transition:all var(--n-transition-fast);line-height:1;display:flex;align-items:center}.n-ac-action:hover:not(:disabled){color:var(--n-color-text);background:var(--n-color-glass)}.n-ac-action:disabled{opacity:0.5;cursor:not-allowed}.n-ac-input-wrap.is-disabled{opacity:0.5;cursor:not-allowed;background:var(--n-color-surface-alt)}.n-ac-popup{background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);box-shadow:var(--n-shadow-lg);overflow:hidden;animation:n-ac-in .2s cubic-bezier(0,1,0,1)}.n-ac-popup.is-top{animation:n-ac-in-top .2s cubic-bezier(0,1,0,1)}@keyframes n-ac-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}@keyframes n-ac-in-top{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.n-ac-loading{padding:var(--n-space-3) var(--n-space-4);color:var(--n-color-text-muted);font-size:var(--n-text-sm)}.n-ac-list{max-height:260px;overflow:auto;display:flex;flex-direction:column}.n-ac-option{text-align:left;padding:0.7rem 1rem;color:var(--n-color-text-secondary);background:transparent;border:none;cursor:pointer;transition:all var(--n-transition-fast)}.n-ac-option:hover,.n-ac-option.is-focused{background:var(--n-color-glass);color:var(--n-color-text)}.n-ac-empty{padding:var(--n-space-4);color:var(--n-color-text-muted);text-align:center;font-size:var(--n-text-sm)}
58
+ </style>
@@ -0,0 +1,75 @@
1
+ import { computed, h, hText, effect, defineComponent, registerComponent, reloadComponent, injectStyle } from 'nexa-framework'
2
+
3
+ const _sfc_main = defineComponent({
4
+ __scopeId: 'data-v-147134',
5
+ __hmrId: 'NAvatar_nexa',
6
+ props: {
7
+ label: { type: String, default: '' },
8
+ size: { type: String, default: 'md' },
9
+ variant: { type: String, default: 'primary' },
10
+ image: { type: String, default: '' },
11
+ shape: { type: String, default: 'rounded' } // rounded, circle, square
12
+ },
13
+ setup(props, setupContext) {
14
+ const { emit, slots, slots: $slots } = setupContext
15
+ const initials = computed(() => {
16
+ if (!props.label) return '?'
17
+ return props.label
18
+ .split(' ')
19
+ .map(w => w[0])
20
+ .join('')
21
+ .toUpperCase()
22
+ .slice(0, 2)
23
+ })
24
+ return { initials, $slots }
25
+ }
26
+ })
27
+ // Injected render function
28
+ _sfc_main.render = function(ctx) {
29
+ const { initials, $slots, label, size, variant, image, shape, Fragment: _ntc_Fragment } = ctx
30
+ return h('div', { class: ['n-avatar', `is-${size}`, `is-${variant}`, `is-${shape}`], vBind: true, style: image ? { backgroundImage: `url(${image})` } : {}, "aria-label": label, "data-v-147134": "" }, [
31
+ "\n ",
32
+ (!image) ? h('span', { class: "n-avatar-initials", "data-v-147134": "" }, [
33
+ initials.value
34
+ ]) : null
35
+ ])
36
+ }
37
+ _sfc_main.__scopeId = 'data-v-147134'
38
+ _sfc_main.__hmrId = 'NAvatar_nexa'
39
+
40
+ export default _sfc_main
41
+
42
+ const __style = `.n-avatar[data-v-147134]{
43
+ display: inline-flex;
44
+ align-items: center;
45
+ justify-content: center;
46
+ flex-shrink: 0;
47
+ background-size: cover;
48
+ background-position: center;
49
+ background-color: var(--n-color-surface-hover);
50
+ font-weight: var(--n-weight-bold);
51
+ color: var(--n-color-text);
52
+ user-select: none;
53
+ transition: all var(--n-transition-fast);
54
+ }
55
+
56
+ .is-sm[data-v-147134]{ width: 32px; height: 32px; font-size: var(--n-text-xs); }
57
+ .is-md[data-v-147134]{ width: 40px; height: 40px; font-size: var(--n-text-sm); }
58
+ .is-lg[data-v-147134]{ width: 56px; height: 56px; font-size: var(--n-text-lg); }
59
+ .is-xl[data-v-147134]{ width: 72px; height: 72px; font-size: var(--n-text-2xl); }
60
+
61
+ .is-circle[data-v-147134]{ border-radius: var(--n-radius-full); }
62
+ .is-rounded[data-v-147134]{ border-radius: var(--n-radius-md); }
63
+ .is-square[data-v-147134]{ border-radius: 0; }
64
+
65
+ .is-primary[data-v-147134]{ background-color: var(--n-color-primary); color: white; }
66
+ .is-success[data-v-147134]{ background-color: var(--n-color-success); color: white; }
67
+ .is-danger[data-v-147134]{ background-color: var(--n-color-danger); color: white; }
68
+ .is-warning[data-v-147134]{ background-color: var(--n-color-warning); color: white; }
69
+ .is-info[data-v-147134]{ background-color: var(--n-color-info); color: white; }
70
+
71
+ .n-avatar-initials[data-v-147134]{
72
+ line-height: 1;
73
+ font-weight: var(--n-weight-bold);
74
+ }`
75
+ injectStyle('data-v-147134', __style)
@@ -0,0 +1,67 @@
1
+ <script setup>
2
+ import { computed } from 'nexa-framework'
3
+
4
+ const props = defineProps({
5
+ label: { type: String, default: '' },
6
+ size: { type: String, default: 'md' },
7
+ variant: { type: String, default: 'primary' },
8
+ image: { type: String, default: '' },
9
+ shape: { type: String, default: 'rounded' } // rounded, circle, square
10
+ })
11
+
12
+ const initials = computed(() => {
13
+ if (!props.label) return '?'
14
+ return props.label
15
+ .split(' ')
16
+ .map(w => w[0])
17
+ .join('')
18
+ .toUpperCase()
19
+ .slice(0, 2)
20
+ })
21
+ </script>
22
+
23
+ <template>
24
+ <div
25
+ :class="['n-avatar', `is-${size}`, `is-${variant}`, `is-${shape}`]"
26
+ v-bind:style="image ? { backgroundImage: `url(${image})` } : {}"
27
+ :aria-label="label"
28
+ >
29
+ <span v-if="!image" class="n-avatar-initials">{{ initials.value }}</span>
30
+ </div>
31
+ </template>
32
+
33
+ <style scoped>
34
+ .n-avatar {
35
+ display: inline-flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ flex-shrink: 0;
39
+ background-size: cover;
40
+ background-position: center;
41
+ background-color: var(--n-color-surface-hover);
42
+ font-weight: var(--n-weight-bold);
43
+ color: var(--n-color-text);
44
+ user-select: none;
45
+ transition: all var(--n-transition-fast);
46
+ }
47
+
48
+ .is-sm { width: 32px; height: 32px; font-size: var(--n-text-xs); }
49
+ .is-md { width: 40px; height: 40px; font-size: var(--n-text-sm); }
50
+ .is-lg { width: 56px; height: 56px; font-size: var(--n-text-lg); }
51
+ .is-xl { width: 72px; height: 72px; font-size: var(--n-text-2xl); }
52
+
53
+ .is-circle { border-radius: var(--n-radius-full); }
54
+ .is-rounded { border-radius: var(--n-radius-md); }
55
+ .is-square { border-radius: 0; }
56
+
57
+ .is-primary { background-color: var(--n-color-primary); color: white; }
58
+ .is-success { background-color: var(--n-color-success); color: white; }
59
+ .is-danger { background-color: var(--n-color-danger); color: white; }
60
+ .is-warning { background-color: var(--n-color-warning); color: white; }
61
+ .is-info { background-color: var(--n-color-info); color: white; }
62
+
63
+ .n-avatar-initials {
64
+ line-height: 1;
65
+ font-weight: var(--n-weight-bold);
66
+ }
67
+ </style>
@@ -0,0 +1,74 @@
1
+ import { h, hText, effect, defineComponent, registerComponent, reloadComponent, injectStyle } from 'nexa-framework'
2
+
3
+ const _sfc_main = defineComponent({
4
+ __scopeId: 'data-v-ff3cf3e',
5
+ __hmrId: 'NBadge_nexa',
6
+ props: {
7
+ variant: { type: String, default: 'primary' },
8
+ size: { type: String, default: 'md' },
9
+ rounded: { type: Boolean, default: false },
10
+ dot: { type: Boolean, default: false },
11
+ position: { type: String, default: '' }
12
+ },
13
+ setup(props, setupContext) {
14
+ const { emit, slots, slots: $slots } = setupContext
15
+ return { $slots }
16
+ }
17
+ })
18
+ // Injected render function
19
+ _sfc_main.render = function(ctx) {
20
+ const { $slots, variant, size, rounded, dot, position, Fragment: _ntc_Fragment } = ctx
21
+ return (dot) ? h('span', { class: ["n-badge-dot", [`is-${variant}`, position ? `is-${position}` : '']], "data-v-ff3cf3e": "" }) : (true) ? h('span', { class: ['n-badge', `n-badge-${variant}`, `n-badge-${size}`, rounded ? 'is-rounded' : ''], "data-v-ff3cf3e": "" }, [
22
+ "\n ",
23
+ ctx.$slots.default ? ctx.$slots.default() : null,
24
+ "\n "
25
+ ]) : null
26
+ }
27
+ _sfc_main.__scopeId = 'data-v-ff3cf3e'
28
+ _sfc_main.__hmrId = 'NBadge_nexa'
29
+
30
+ export default _sfc_main
31
+
32
+ const __style = `.n-badge[data-v-ff3cf3e]{
33
+ display: inline-flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ padding: 0.25rem 0.6rem;
37
+ font-size: var(--n-text-xs);
38
+ font-weight: var(--n-weight-bold);
39
+ border-radius: var(--n-radius-sm);
40
+ line-height: 1;
41
+ font-family: var(--n-font-sans);
42
+ text-transform: uppercase;
43
+ letter-spacing: var(--n-tracking-wide);
44
+ transition: all var(--n-transition-fast);
45
+ }
46
+
47
+ .n-badge-primary[data-v-ff3cf3e]{ background: var(--n-color-primary); color: white; }
48
+ .n-badge-success[data-v-ff3cf3e]{ background: var(--n-color-success); color: white; }
49
+ .n-badge-danger[data-v-ff3cf3e]{ background: var(--n-color-danger); color: white; }
50
+ .n-badge-warning[data-v-ff3cf3e]{ background: var(--n-color-warning); color: white; }
51
+ .n-badge-info[data-v-ff3cf3e]{ background: var(--n-color-info); color: white; }
52
+ .n-badge-secondary[data-v-ff3cf3e]{ background: var(--n-color-surface-hover); color: var(--n-color-text-secondary); }
53
+
54
+ .n-badge-sm[data-v-ff3cf3e]{ padding: 0.15rem 0.4rem; font-size: 0.65rem; }
55
+ .n-badge-lg[data-v-ff3cf3e]{ padding: 0.4rem 0.8rem; font-size: var(--n-text-sm); }
56
+
57
+ .is-rounded[data-v-ff3cf3e]{ border-radius: var(--n-radius-full); }
58
+
59
+ .n-badge-dot[data-v-ff3cf3e]{
60
+ display: inline-block;
61
+ width: 8px;
62
+ height: 8px;
63
+ border-radius: var(--n-radius-full);
64
+ vertical-align: middle;
65
+ flex-shrink: 0;
66
+ }
67
+
68
+ .n-badge-dot.is-primary[data-v-ff3cf3e]{ background: var(--n-color-primary); }
69
+ .n-badge-dot.is-success[data-v-ff3cf3e]{ background: var(--n-color-success); }
70
+ .n-badge-dot.is-danger[data-v-ff3cf3e]{ background: var(--n-color-danger); }
71
+ .n-badge-dot.is-warning[data-v-ff3cf3e]{ background: var(--n-color-warning); }
72
+ .n-badge-dot.is-info[data-v-ff3cf3e]{ background: var(--n-color-info); }
73
+ .n-badge-dot.is-secondary[data-v-ff3cf3e]{ background: var(--n-color-text-muted); }`
74
+ injectStyle('data-v-ff3cf3e', __style)
@@ -0,0 +1,61 @@
1
+ <script setup>
2
+ const props = defineProps({
3
+ variant: { type: String, default: 'primary' },
4
+ size: { type: String, default: 'md' },
5
+ rounded: { type: Boolean, default: false },
6
+ dot: { type: Boolean, default: false },
7
+ position: { type: String, default: '' }
8
+ })
9
+ </script>
10
+
11
+ <template>
12
+ <span v-if="dot" class="n-badge-dot" :class="[`is-${variant}`, position ? `is-${position}` : '']"></span>
13
+ <span v-else :class="['n-badge', `n-badge-${variant}`, `n-badge-${size}`, rounded ? 'is-rounded' : '']">
14
+ <slot />
15
+ </span>
16
+ </template>
17
+
18
+ <style scoped>
19
+ .n-badge {
20
+ display: inline-flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ padding: 0.25rem 0.6rem;
24
+ font-size: var(--n-text-xs);
25
+ font-weight: var(--n-weight-bold);
26
+ border-radius: var(--n-radius-sm);
27
+ line-height: 1;
28
+ font-family: var(--n-font-sans);
29
+ text-transform: uppercase;
30
+ letter-spacing: var(--n-tracking-wide);
31
+ transition: all var(--n-transition-fast);
32
+ }
33
+
34
+ .n-badge-primary { background: var(--n-color-primary); color: white; }
35
+ .n-badge-success { background: var(--n-color-success); color: white; }
36
+ .n-badge-danger { background: var(--n-color-danger); color: white; }
37
+ .n-badge-warning { background: var(--n-color-warning); color: white; }
38
+ .n-badge-info { background: var(--n-color-info); color: white; }
39
+ .n-badge-secondary { background: var(--n-color-surface-hover); color: var(--n-color-text-secondary); }
40
+
41
+ .n-badge-sm { padding: 0.15rem 0.4rem; font-size: 0.65rem; }
42
+ .n-badge-lg { padding: 0.4rem 0.8rem; font-size: var(--n-text-sm); }
43
+
44
+ .is-rounded { border-radius: var(--n-radius-full); }
45
+
46
+ .n-badge-dot {
47
+ display: inline-block;
48
+ width: 8px;
49
+ height: 8px;
50
+ border-radius: var(--n-radius-full);
51
+ vertical-align: middle;
52
+ flex-shrink: 0;
53
+ }
54
+
55
+ .n-badge-dot.is-primary { background: var(--n-color-primary); }
56
+ .n-badge-dot.is-success { background: var(--n-color-success); }
57
+ .n-badge-dot.is-danger { background: var(--n-color-danger); }
58
+ .n-badge-dot.is-warning { background: var(--n-color-warning); }
59
+ .n-badge-dot.is-info { background: var(--n-color-info); }
60
+ .n-badge-dot.is-secondary { background: var(--n-color-text-muted); }
61
+ </style>
@@ -0,0 +1,149 @@
1
+ import { signal, computed, effect, onMounted, onUnmounted, h, hText, defineComponent, registerComponent, reloadComponent, injectStyle, Teleport } from 'nexa-framework'
2
+ import { useGestures } from 'nexa-mobile'
3
+
4
+ const _sfc_main = defineComponent({
5
+ __scopeId: 'data-v-55f61938',
6
+ __hmrId: 'NBottomSheet_nexa',
7
+ props: {
8
+ show: { type: Boolean, default: false },
9
+ snapPoints: { type: Array, default: () => [50, 80] }
10
+ },
11
+ emits: ['close'],
12
+ setup(props, setupContext) {
13
+ const { emit, slots, slots: $slots } = setupContext
14
+ const yOffset = signal(0)
15
+ const isDragging = signal(false)
16
+ const currentSnap = signal(0)
17
+ let gestures = null
18
+ const sortedPoints = computed(() =>
19
+ [...props.snapPoints].sort((a, b) => a - b)
20
+ )
21
+ onMounted(() => {
22
+ const el = document.getElementById('n-bottom-sheet-content')
23
+ if (el) {
24
+ gestures = useGestures(el)
25
+ effect(() => {
26
+ if (gestures.isSwiping.value && gestures.swipeDirection.value === 'down') {
27
+ isDragging.value = true
28
+ yOffset.value = Math.max(0, gestures.deltaY.value)
29
+ } else if (!gestures.isPressed.value) {
30
+ if (isDragging.value) {
31
+ isDragging.value = false
32
+ const maxSnap = sortedPoints.value[sortedPoints.value.length - 1]
33
+ const threshold = window.innerHeight * (maxSnap / 100) * 0.3
34
+ if (yOffset.value > threshold) {
35
+ emit('close')
36
+ yOffset.value = 0
37
+ return
38
+ }
39
+ }
40
+ yOffset.value = 0
41
+ }
42
+ })
43
+ }
44
+ })
45
+ onUnmounted(() => {
46
+ gestures?.destroy()
47
+ })
48
+ const translateY = computed(() => {
49
+ if (!props.show) return '100%'
50
+ const base = window.innerHeight * (1 - sortedPoints.value[currentSnap.value] / 100)
51
+ return `${base + yOffset.value}px`
52
+ })
53
+ const overlayOpacity = computed(() => {
54
+ if (!props.show) return 0
55
+ const progress = 1 - (yOffset.value / (window.innerHeight * 0.5))
56
+ return Math.max(0, Math.min(1, progress))
57
+ })
58
+ return { yOffset, isDragging, currentSnap, gestures, sortedPoints, translateY, overlayOpacity, useGestures, $slots, emit }
59
+ }
60
+ })
61
+ // Injected render function
62
+ _sfc_main.render = function(ctx) {
63
+ const { yOffset, isDragging, currentSnap, gestures, sortedPoints, translateY, overlayOpacity, useGestures, $slots, emit, show, snapPoints, Fragment: _ntc_Fragment, Teleport: _ntc_Teleport } = ctx
64
+ return h(_ntc_Teleport, { to: "body", "data-v-55f61938": "" }, [
65
+ "\n ",
66
+ h('div', { class: ["n-bottom-sheet-root", { 'is-active': show || isDragging.value }], "data-v-55f61938": "" }, [
67
+ "\n ",
68
+ h('div', { class: "n-bottom-sheet-overlay", style: { opacity: overlayOpacity.value }, onClick: ($event) => { emit('close') }, "data-v-55f61938": "" }),
69
+ "\n ",
70
+ h('div', { class: "n-bottom-sheet-container", id: "n-bottom-sheet-content", style: {
71
+ transform: `translateY(${translateY.value})`,
72
+ transition: isDragging.value ? 'none' : 'transform 0.4s cubic-bezier(0.4, 0, 0.2, 1)'
73
+ }, "data-v-55f61938": "" }, [
74
+ "\n ",
75
+ h('div', { class: "n-bottom-sheet-handle", "data-v-55f61938": "" }),
76
+ "\n ",
77
+ h('div', { class: "n-bottom-sheet-inner", "data-v-55f61938": "" }, [
78
+ "\n ",
79
+ ctx.$slots.default ? ctx.$slots.default() : null,
80
+ "\n "
81
+ ]),
82
+ "\n "
83
+ ]),
84
+ "\n "
85
+ ]),
86
+ "\n "
87
+ ])
88
+ }
89
+ _sfc_main.__scopeId = 'data-v-55f61938'
90
+ _sfc_main.__hmrId = 'NBottomSheet_nexa'
91
+
92
+ export default _sfc_main
93
+
94
+ const __style = `.n-bottom-sheet-root[data-v-55f61938]{
95
+ position: fixed;
96
+ top: 0;
97
+ left: 0;
98
+ width: 100vw;
99
+ height: 100vh;
100
+ z-index: var(--n-z-modal);
101
+ pointer-events: none;
102
+ display: flex;
103
+ align-items: flex-end;
104
+ }
105
+
106
+ .n-bottom-sheet-root.is-active[data-v-55f61938]{
107
+ pointer-events: auto;
108
+ }
109
+
110
+ .n-bottom-sheet-overlay[data-v-55f61938]{
111
+ position: absolute;
112
+ top: 0;
113
+ left: 0;
114
+ width: 100%;
115
+ height: 100%;
116
+ background: var(--n-color-overlay);
117
+ backdrop-filter: blur(4px);
118
+ transition: opacity 0.3s ease;
119
+ }
120
+
121
+ .n-bottom-sheet-container[data-v-55f61938]{
122
+ position: relative;
123
+ width: 100%;
124
+ max-height: 90vh;
125
+ background: var(--n-color-surface);
126
+ border-top: 1px solid var(--n-color-border);
127
+ border-radius: var(--n-radius-2xl) var(--n-radius-2xl) 0 0;
128
+ box-shadow: 0 -10px 25px -5px rgba(0, 0, 0, 0.3);
129
+ padding-bottom: env(safe-area-inset-bottom, 20px);
130
+ touch-action: none;
131
+ display: flex;
132
+ flex-direction: column;
133
+ }
134
+
135
+ .n-bottom-sheet-handle[data-v-55f61938]{
136
+ width: 40px;
137
+ height: 4px;
138
+ background: var(--n-color-surface-hover);
139
+ border-radius: var(--n-radius-full);
140
+ margin: var(--n-space-3) auto;
141
+ flex-shrink: 0;
142
+ }
143
+
144
+ .n-bottom-sheet-inner[data-v-55f61938]{
145
+ padding: var(--n-space-4) var(--n-space-8) var(--n-space-8);
146
+ overflow-y: auto;
147
+ flex: 1;
148
+ }`
149
+ injectStyle('data-v-55f61938', __style)