Skip to content

Commit f27f19f

Browse files
committed
feat: added spacing prop
1 parent 328ebf3 commit f27f19f

File tree

15 files changed

+238
-68
lines changed

15 files changed

+238
-68
lines changed

packages/anu-vue/src/components/alert/AAlert.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { defineComponent, ref, toRef, watch } from 'vue'
22
import { useLayer, useProps as useLayerProps } from '@/composables/useLayer'
3+
import { spacingProp, useSpacing } from '@/composables/useSpacing'
34

45
export const AAlert = defineComponent({
56
name: 'AAlert',
67
props: {
8+
spacing: spacingProp,
79
...useLayerProps({
810
color: {
911
default: 'primary',
@@ -46,6 +48,7 @@ export const AAlert = defineComponent({
4648
},
4749
},
4850
setup(props, { slots, emit }) {
51+
const spacing = useSpacing(toRef(props, 'spacing'))
4952
const { getLayerClasses } = useLayer()
5053
const { styles, classes } = getLayerClasses(
5154
toRef(props, 'color'),
@@ -70,12 +73,13 @@ export const AAlert = defineComponent({
7073
}
7174

7275
// TODO: Omit writing `props.modelValue ??` multiple times
73-
return () => <div class={['a-alert items-start w-full', props.modelValue ?? isAlertVisible.value ? 'flex' : 'hidden', ...classes.value]} style={[...styles.value]}>
74-
{props.icon ? <i class={props.icon}></i> : null}
76+
return () => <div style={{ '--a-spacing': spacing.value / 100 }} class={['a-alert items-start w-full', props.modelValue ?? isAlertVisible.value ? 'flex' : 'hidden', ...classes.value]} style={[...styles.value]}>
77+
{/* ℹ️ We need div as wrapper with span having `vertical-align: text-top` to center the icon with the text */}
78+
{props.icon ? <div><span class={props.icon}></span></div> : null}
7579
<div class="flex-grow">{slots.default?.()}</div>
7680
{
7781
appendIcon
78-
? <i class={[appendIcon, { 'cursor-pointer': props.dismissible }]} onClick={handleAppendIconClick}></i>
82+
? <div><span class={['align-text-top', appendIcon, { 'cursor-pointer': props.dismissible }]} onClick={handleAppendIconClick}></span></div>
7983
: null
8084
}
8185
</div>

packages/anu-vue/src/components/avatar/AAvatar.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { computed, defineComponent, toRef } from 'vue'
22
import { avatarOnlyProps } from '@/components/avatar/props'
33
import { useLayer, useProps as useLayerProps } from '@/composables/useLayer'
4+
import { spacingProp, useSpacing } from '@/composables/useSpacing'
45

56
export const AAvatar = defineComponent({
67
name: 'AAvatar',
78
props: {
9+
spacing: spacingProp,
810
...useLayerProps({
911
color: {
1012
default: 'primary',
@@ -16,6 +18,7 @@ export const AAvatar = defineComponent({
1618
...avatarOnlyProps,
1719
},
1820
setup(props, { slots }) {
21+
const spacing = useSpacing(toRef(props, 'spacing'))
1922
const { getLayerClasses } = useLayer()
2023
const { styles, classes } = getLayerClasses(
2124
toRef(props, 'color'),
@@ -32,7 +35,7 @@ export const AAvatar = defineComponent({
3235
return props.content
3336
})
3437

35-
return () => <div class={['a-avatar overflow-hidden uno-layer-base-text-2xl em:h-8 em:w-8 inline-flex items-center justify-center uno-layer-base-rounded-full', ...classes.value]} style={[...styles.value]}>
38+
return () => <div style={{ '--a-spacing': spacing.value / 100 }} class={['a-avatar overflow-hidden inline-flex items-center justify-center', ...classes.value]} style={[...styles.value]}>
3639
{
3740
slots.default
3841
? slots.default()

packages/anu-vue/src/components/badge/ABadge.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { PropType } from 'vue'
2-
import { computed, defineComponent } from 'vue'
2+
import { computed, defineComponent, toRef } from 'vue'
33
import { color } from '@/composables/useProps'
4+
import { spacingProp, useSpacing } from '@/composables/useSpacing'
45
import { isNumeric } from '@/utils/helpers'
56

67
export type VerticalAnchor = 'top' | 'bottom'
@@ -12,7 +13,9 @@ const defaultOverlapOffset = 12
1213

1314
export const ABadge = defineComponent({
1415
name: 'ABadge',
16+
inheritAttrs: false,
1517
props: {
18+
spacing: spacingProp,
1619
color: {
1720
...color,
1821
default: 'primary',
@@ -50,7 +53,8 @@ export const ABadge = defineComponent({
5053
default: defaultOffset,
5154
},
5255
},
53-
setup(props, { slots }) {
56+
setup(props, { slots, attrs }) {
57+
const spacing = useSpacing(toRef(props, 'spacing'))
5458
const formatMaxContent = (content: unknown) => {
5559
if (!isNumeric(content))
5660
return content
@@ -92,7 +96,7 @@ export const ABadge = defineComponent({
9296

9397
return () => <div class={['a-badge-wrapper relative']}>
9498
{slots.default?.()}
95-
<div class={[`a-badge bg-${props.color} absolute`, { 'a-badge-dot': props.dot }, { 'a-badge-bordered': props.bordered }]} style={positionStyles.value}>
99+
<div {...attrs} style={{ '--a-spacing': spacing.value / 100 }} class={[`a-badge bg-${props.color} absolute`, { 'a-badge-dot': props.dot }, { 'a-badge-bordered': props.bordered }]} style={positionStyles.value}>
96100
{badgeSlotContent.value}
97101
</div>
98102
</div>

packages/anu-vue/src/components/base-input/ABaseInput.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import type { PropType } from 'vue'
2-
import { defineComponent, ref } from 'vue'
2+
import { defineComponent, ref, toRef } from 'vue'
33
import { disabled, readonly } from '@/composables/useProps'
4+
import { spacingProp, useSpacing } from '@/composables/useSpacing'
45
import TransitionExpand from '@/transitions/TransitionExpand.vue'
56

67
export const ABaseInput = defineComponent({
78
name: 'ABaseInput',
89
inheritAttrs: false,
910
props: {
11+
spacing: spacingProp,
1012
inputWrapperClasses: [Array, String, Object] as PropType<string | string[] | object>,
1113
inputContainerAttrs: Object,
1214
hint: String,
@@ -20,6 +22,7 @@ export const ABaseInput = defineComponent({
2022
readonly,
2123
},
2224
setup(props, { attrs, slots, expose }) {
25+
const spacing = useSpacing(toRef(props, 'spacing'))
2326
const iconTransition = 'transition duration-150 ease -in'
2427
const elementId = attrs.id || props.label ? `a-input-${attrs.id || props.label}-${Math.random().toString(36).slice(2, 7)}` : undefined
2528

@@ -32,7 +35,7 @@ export const ABaseInput = defineComponent({
3235

3336
// TODO(Enhancement): We might need to remove absolute added to html input element to retain width instead of providing min-w to below wrapper
3437
// TODO: We need to improve default slot implementation so that we can provide selected slot to selection component
35-
return () => <div class={['a-base-input-root i:children:focus-within:text-primary flex flex-col flex-grow flex-shrink-0', attrs.class ?? [], props.disabled && 'a-base-input-disabled ', (props.disabled || props.readonly) && 'pointer-events-none', !(props.disabled || props.readonly) && 'a-base-input-interactive']} ref={refRoot}>
38+
return () => <div style={{ '--a-spacing': spacing.value / 100 }} class={['a-base-input-root i:children:focus-within:text-primary flex flex-col flex-grow flex-shrink-0', attrs.class ?? [], props.disabled && 'a-base-input-disabled ', (props.disabled || props.readonly) && 'pointer-events-none', !(props.disabled || props.readonly) && 'a-base-input-interactive']} ref={refRoot}>
3639
{/* 👉 Label */}
3740
{
3841
slots.label

packages/anu-vue/src/components/btn/ABtn.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { defineComponent, toRef } from 'vue'
22
import { useLayer, useProps as useLayerProps } from '@/composables/useLayer'
33
import { disabled } from '@/composables/useProps'
4+
import { spacingProp, useSpacing } from '@/composables/useSpacing'
45

56
export const ABtn = defineComponent({
67
name: 'ABtn',
78
props: {
9+
spacing: spacingProp,
10+
811
/*
912
ℹ️ If we want volar to infer the correct default values for prop we need to enable below three lines because volar can't generate correct data for dynamic code
1013
Please refer to this gen-component-meta script's useful links for more details
@@ -54,6 +57,7 @@ export const ABtn = defineComponent({
5457
disabled,
5558
},
5659
setup(props, { slots, attrs: _ }) {
60+
const spacing = useSpacing(toRef(props, 'spacing'))
5761
const { getLayerClasses } = useLayer()
5862

5963
const { styles, classes } = getLayerClasses(
@@ -63,7 +67,7 @@ export const ABtn = defineComponent({
6367
)
6468

6569
// FIX: ABtn gets full width if placed inside flex container
66-
return () => <button class={[props.iconOnly ? 'a-btn-icon-only' : 'a-btn', 'uno-layer-base-text-base whitespace-nowrap inline-flex justify-center items-center', { 'opacity-50 pointer-events-none': props.disabled }, ...classes.value]} style={[...styles.value]}>
70+
return () => <button style={{ '--a-spacing': spacing.value / 100 }} class={[props.iconOnly ? 'a-btn-icon-only' : 'a-btn', 'whitespace-nowrap inline-flex justify-center items-center', { 'opacity-50 pointer-events-none': props.disabled }, ...classes.value]} style={[...styles.value]}>
6771
{props.icon ? <i class={props.icon}></i> : null}{slots.default?.()}{props.appendIcon ? <i class={props.appendIcon}></i> : null}
6872
</button>
6973
},

packages/anu-vue/src/components/card/ACard.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { defineComponent, reactive, toRef, toRefs } from 'vue'
22
import { ATypography } from '../typography'
33
import { useLayer, useProps as useLayerProps } from '@/composables/useLayer'
4+
import { spacingProp, useSpacing } from '@/composables/useSpacing'
45
import { extractTypographyProp, isTypographyUsed, useTypographyProps } from '@/composables/useTypography'
56

67
export const ACard = defineComponent({
78
name: 'ACard',
89
props: {
10+
spacing: spacingProp,
911
...useLayerProps({
1012
variant: {
1113
default: 'text',
@@ -22,6 +24,7 @@ export const ACard = defineComponent({
2224
},
2325
},
2426
setup(props, { slots }) {
27+
const spacing = useSpacing(toRef(props, 'spacing'))
2528
const { getLayerClasses } = useLayer()
2629
const { styles, classes } = getLayerClasses(
2730
toRef(props, 'color'),
@@ -45,7 +48,7 @@ export const ACard = defineComponent({
4548
}
4649
}
4750

48-
return () => <div class={['a-card overflow-hidden uno-layer-base-text-sm uno-layer-base-bg-[hsl(var(--a-layer))]', ...classes.value]} style={[...styles.value]}>
51+
return () => <div style={{ '--a-spacing': spacing.value / 100 }} class={['a-card overflow-hidden uno-layer-base-bg-[hsl(var(--a-layer))]', ...classes.value]} style={[...styles.value]}>
4952
{/* 👉 Image */}
5053
{props.img ? <img src={props.img} alt="card-img"></img> : null}
5154

packages/anu-vue/src/components/table/ATable.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { computedEager, useOffsetPagination } from '@vueuse/core'
22
import type { ComputedRef, PropType, Ref, ToRefs } from 'vue'
3-
import { computed, defineComponent, reactive, ref, toRaw, toRefs, watch } from 'vue'
3+
import { computed, defineComponent, reactive, ref, toRaw, toRef, toRefs, watch } from 'vue'
44
import { ABtn } from '@/components/btn'
55
import { ACard, useCardProps } from '@/components/card'
66
import { AInput } from '@/components/input'
@@ -10,6 +10,7 @@ import type { CustomFilter } from '@/composables/useSearch'
1010
import { useSearch } from '@/composables/useSearch'
1111
import type { CustomSort, typeSortBy } from '@/composables/useSort'
1212
import { useSort } from '@/composables/useSort'
13+
import { spacingProp, useSpacing } from '@/composables/useSpacing'
1314

1415
export type ShallSortByAsc = boolean | null
1516

@@ -100,10 +101,13 @@ const tableProps = {
100101
export const ATable = defineComponent({
101102
name: 'ATable',
102103
props: {
104+
spacing: spacingProp,
103105
...useCardProps(),
104106
...tableProps,
105107
},
106108
setup(props, { slots }) {
109+
const spacing = useSpacing(toRef(props, 'spacing'))
110+
107111
// ℹ️ I used destructing to extract card props from table props. Moreover,I didn't wanted to use destructured props hence I omitted them
108112

109113
const cardProps = computed<Partial<ToRefs<typeof props>>>(() => {
@@ -391,10 +395,10 @@ export const ATable = defineComponent({
391395
slots[`row-${col.name}`]
392396
? slots[`row-${col.name}`]?.({ row })
393397
: col.formatter
394-
? col.formatter?.(row)
398+
? <span class="a-table-td-text">{col.formatter?.(row)}</span>
395399

396400
// TODO(TS): Improve typing
397-
: row[col.name as keyof Object]
401+
: <span class="a-table-td-text">{row[col.name as keyof Object]}</span>
398402
}
399403
</td>,
400404
)
@@ -412,16 +416,16 @@ export const ATable = defineComponent({
412416
// 👉 Footer
413417
// TODO: create PR for useOffsetPagination metadata
414418
const tableFooter = <div class="a-table-footer flex items-center">
415-
<ATypography class="text-size-[inherit]" v-slots={{
416-
subtitle: () => <>
417-
{rowsToRender.value.length ? (currentPage.value - 1) * currentPageSize.value + 1 : 0} - {isLastPage ? rowsToRender.value.length : currentPage.value * currentPageSize.value} of {total.value}
418-
</>,
419-
}}></ATypography>
419+
<ATypography class="a-table-pagination-meta">
420+
{/* TODO: Remove this text-xs usage as we have text-xs in default theme's styles once we resolve the card font size issue */}
421+
<span class="text-xs">{rowsToRender.value.length ? (currentPage.value - 1) * currentPageSize.value + 1 : 0} - {isLastPage ? rowsToRender.value.length : currentPage.value * currentPageSize.value} of {total.value}</span>
422+
</ATypography>
420423
<div class="flex-grow"></div>
421424
<div class="a-table-footer-per-page-container flex items-center">
422425
<span class="sm:inline hidden">per page</span>
423426
<ASelect
424427
class="a-table-footer-per-page-select"
428+
spacing={80}
425429
inputWrapperClasses="a-table-footer-per-page-select--input-wrapper-classes"
426430
optionsWrapperClasses="a-table-footer-per-page-select--options-wrapper-classes"
427431
v-model={currentPageSize.value}
@@ -437,6 +441,7 @@ export const ATable = defineComponent({
437441
// TODO: noresultstext is represented as attrs of card
438442
// 💡 Here we are passing all the slots to card except default which gets overridden for merging provided default slot with table
439443
return <ACard
444+
style={{ '--a-spacing': spacing.value / 100 }}
440445
class="a-table"
441446
{...reactive(cardProps.value)}
442447
v-slots={{
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { App, ComputedRef, Ref } from 'vue'
2+
import { computed, inject, provide } from 'vue'
3+
import { spacingSymbol } from '@/symbols'
4+
5+
/*
6+
ℹ️ Why we are using provide/inject and not relying on CSS var?
7+
A: Because, When we render the element outside of the DOM tree, like dialog, selection options, etc. CSS var don't get applied there.
8+
We can use provided value (by parent) to apply the spacing.
9+
10+
Assume, we are working on select component. To overcome above mentioned DOM tree issue we can use JS to get the CSS var value attached to the component,
11+
but we can't watch it. Hence, we have to use provide/inject instead of CSS var.
12+
*/
13+
14+
export const provideAppSpacing = (app: App) => {
15+
app.provide(spacingSymbol, 100)
16+
}
17+
18+
export const useSpacing = (spacing: Ref<number | undefined>): ComputedRef<number> => {
19+
const injectedSpacing = inject(spacingSymbol, 100)
20+
21+
const _spacing = computed(() => spacing.value || injectedSpacing)
22+
23+
provide(spacingSymbol, _spacing.value)
24+
25+
return _spacing
26+
}
27+
28+
/**
29+
* Modify component and its children spacing
30+
*/
31+
export const spacingProp = {
32+
type: Number,
33+
default: undefined,
34+
}

packages/anu-vue/src/index.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
import type { App } from 'vue'
22
import * as components from './components'
3+
import { provideAppSpacing } from '@/composables/useSpacing'
34
import './presets/theme-default/scss/index.scss'
45
import './scss/index.scss'
56

7+
export interface PluginOptions {
8+
registerComponents: boolean
9+
}
10+
611
const plugin = {
7-
install(app: App) {
12+
install(app: App, options?: PluginOptions) {
13+
provideAppSpacing(app)
14+
815
// console.log('components :>> ', components);
9-
for (const prop in components) {
16+
if (options && options.registerComponents) {
17+
for (const prop in components) {
1018
// @ts-expect-error: I want to index import using string
11-
const component = components[prop]
12-
app.component(component.name, component)
19+
const component = components[prop]
20+
app.component(component.name, component)
21+
}
1322
}
1423
},
1524
}
@@ -21,5 +30,6 @@ export { presetCore } from './presets/core'
2130
export {
2231
colors as defaultThemeColors, presetThemeDefault,
2332
} from './presets/theme-default'
33+
export * from './symbols'
2434
export { plugin as anu }
2535

0 commit comments

Comments
 (0)