@ui0/theme 0.0.0-stage → 0.1.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 (148) hide show
  1. package/README.md +113 -2
  2. package/dist/backdrop.module.css +1 -0
  3. package/dist/backdrop.scss +7 -0
  4. package/dist/color.inject.module.css +7 -0
  5. package/dist/color.module.css +3 -0
  6. package/dist/color.scss +84 -0
  7. package/dist/components/index.d.ts +4 -0
  8. package/dist/components/index.d.ts.map +1 -0
  9. package/dist/components/index.js +53 -0
  10. package/dist/components/style.css +1 -0
  11. package/dist/components/theme-provider.keys.d.ts +4 -0
  12. package/dist/components/theme-provider.keys.d.ts.map +1 -0
  13. package/dist/components/theme-provider.module.css +1 -0
  14. package/dist/components/theme-provider.types.d.ts +18 -0
  15. package/dist/components/theme-provider.types.d.ts.map +1 -0
  16. package/dist/components/theme-provider.vue.d.ts +19 -0
  17. package/dist/config.default.d.mts +4 -0
  18. package/dist/config.default.d.mts.map +1 -0
  19. package/dist/config.default.mjs +73 -0
  20. package/dist/config.default.mjs.map +1 -0
  21. package/dist/disabled.inject.module.css +5 -0
  22. package/dist/disabled.module.css +1 -0
  23. package/dist/disabled.scss +3 -0
  24. package/dist/display.module.css +2 -0
  25. package/dist/display.scss +63 -0
  26. package/dist/duration.scss +17 -0
  27. package/dist/elevation.module.css +33 -0
  28. package/dist/elevation.scss +46 -0
  29. package/dist/generate-BPYE5ALG.mjs +1037 -0
  30. package/dist/generate-BPYE5ALG.mjs.map +1 -0
  31. package/dist/generator/cli.d.mts +1 -0
  32. package/dist/generator/cli.mjs +103 -0
  33. package/dist/generator/cli.mjs.map +1 -0
  34. package/dist/generator/vite.d.mts +18 -0
  35. package/dist/generator/vite.d.mts.map +1 -0
  36. package/dist/generator/vite.mjs +117 -0
  37. package/dist/generator/vite.mjs.map +1 -0
  38. package/dist/index.d.mts +339 -0
  39. package/dist/index.d.mts.map +1 -0
  40. package/dist/index.mjs +909 -0
  41. package/dist/index.mjs.map +1 -0
  42. package/dist/is.scss +185 -0
  43. package/dist/load-config-64q6nzFy.mjs +48 -0
  44. package/dist/load-config-64q6nzFy.mjs.map +1 -0
  45. package/dist/ripple.scss +57 -0
  46. package/dist/round.inject.module.css +92 -0
  47. package/dist/round.module.css +14 -0
  48. package/dist/round.scss +90 -0
  49. package/dist/size.inject.module.css +50 -0
  50. package/dist/size.module.css +13 -0
  51. package/dist/size.scss +28 -0
  52. package/dist/theme.scss +16 -0
  53. package/dist/typography.inject.module.css +81 -0
  54. package/dist/typography.module.css +32 -0
  55. package/dist/typography.scss +21 -0
  56. package/dist/util.scss +78 -0
  57. package/dist/vars.scss +0 -0
  58. package/package.json +96 -4
  59. package/src/contracts/backdrop/backdrop.contract.ts +44 -0
  60. package/src/contracts/backdrop/backdrop.generator.ts +82 -0
  61. package/src/contracts/backdrop/backdrop.keys.ts +7 -0
  62. package/src/contracts/backdrop/backdrop.module.css +3 -0
  63. package/src/contracts/backdrop/backdrop.scss +7 -0
  64. package/src/contracts/backdrop/backdrop.types.ts +45 -0
  65. package/src/contracts/backdrop/index.ts +21 -0
  66. package/src/contracts/color/color.contract.spec.ts +75 -0
  67. package/src/contracts/color/color.contract.ts +97 -0
  68. package/src/contracts/color/color.generator.spec.ts +73 -0
  69. package/src/contracts/color/color.generator.ts +122 -0
  70. package/src/contracts/color/color.gradient.spec.ts +32 -0
  71. package/src/contracts/color/color.gradient.ts +52 -0
  72. package/src/contracts/color/color.inject.module.css +5 -0
  73. package/src/contracts/color/color.keys.ts +7 -0
  74. package/src/contracts/color/color.module.css +5 -0
  75. package/src/contracts/color/color.scss +84 -0
  76. package/src/contracts/color/color.serialize.spec.ts +57 -0
  77. package/src/contracts/color/color.serialize.ts +35 -0
  78. package/src/contracts/color/color.token.spec.ts +57 -0
  79. package/src/contracts/color/color.token.ts +89 -0
  80. package/src/contracts/color/color.types.ts +82 -0
  81. package/src/contracts/color/index.md +87 -0
  82. package/src/contracts/color/index.ts +25 -0
  83. package/src/contracts/contract.ts +115 -0
  84. package/src/contracts/disabled/disabled.contract.ts +32 -0
  85. package/src/contracts/disabled/disabled.generator.ts +32 -0
  86. package/src/contracts/disabled/disabled.inject.module.css +5 -0
  87. package/src/contracts/disabled/disabled.keys.ts +6 -0
  88. package/src/contracts/disabled/disabled.module.css +3 -0
  89. package/src/contracts/disabled/disabled.scss +3 -0
  90. package/src/contracts/disabled/disabled.types.ts +19 -0
  91. package/src/contracts/disabled/index.ts +21 -0
  92. package/src/contracts/display/display.contract.ts +41 -0
  93. package/src/contracts/display/display.generator.ts +57 -0
  94. package/src/contracts/display/display.instance.ts +173 -0
  95. package/src/contracts/display/display.keys.ts +9 -0
  96. package/src/contracts/display/display.module.css +4 -0
  97. package/src/contracts/display/display.scss +63 -0
  98. package/src/contracts/display/display.types.ts +75 -0
  99. package/src/contracts/display/index.ts +27 -0
  100. package/src/contracts/elevation/elevation.contract.ts +37 -0
  101. package/src/contracts/elevation/elevation.generator.ts +71 -0
  102. package/src/contracts/elevation/elevation.keys.ts +6 -0
  103. package/src/contracts/elevation/elevation.module.css +35 -0
  104. package/src/contracts/elevation/elevation.scss +46 -0
  105. package/src/contracts/elevation/elevation.types.ts +21 -0
  106. package/src/contracts/elevation/index.ts +20 -0
  107. package/src/contracts/generator.ts +38 -0
  108. package/src/contracts/index.md +48 -0
  109. package/src/contracts/index.ts +37 -0
  110. package/src/contracts/round/index.ts +21 -0
  111. package/src/contracts/round/round.contract.ts +75 -0
  112. package/src/contracts/round/round.generator.ts +33 -0
  113. package/src/contracts/round/round.inject.module.scss +36 -0
  114. package/src/contracts/round/round.keys.ts +7 -0
  115. package/src/contracts/round/round.module.css +16 -0
  116. package/src/contracts/round/round.scss +90 -0
  117. package/src/contracts/round/round.types.ts +44 -0
  118. package/src/contracts/size/index.ts +22 -0
  119. package/src/contracts/size/size.contract.ts +98 -0
  120. package/src/contracts/size/size.generator.spec.ts +101 -0
  121. package/src/contracts/size/size.generator.ts +51 -0
  122. package/src/contracts/size/size.inject.module.scss +12 -0
  123. package/src/contracts/size/size.keys.ts +8 -0
  124. package/src/contracts/size/size.module.css +15 -0
  125. package/src/contracts/size/size.scss +28 -0
  126. package/src/contracts/size/size.types.ts +63 -0
  127. package/src/contracts/size/units.scss +17 -0
  128. package/src/contracts/style/index.ts +11 -0
  129. package/src/contracts/style/style.generator.ts +36 -0
  130. package/src/contracts/style/style.key.ts +4 -0
  131. package/src/contracts/style/style.types.ts +16 -0
  132. package/src/contracts/typography/index.ts +26 -0
  133. package/src/contracts/typography/typography.contract.ts +52 -0
  134. package/src/contracts/typography/typography.generator.spec.ts +48 -0
  135. package/src/contracts/typography/typography.generator.ts +44 -0
  136. package/src/contracts/typography/typography.inject.module.css +54 -0
  137. package/src/contracts/typography/typography.keys.ts +12 -0
  138. package/src/contracts/typography/typography.module.css +36 -0
  139. package/src/contracts/typography/typography.scss +21 -0
  140. package/src/contracts/typography/typography.types.ts +90 -0
  141. package/src/generator/theme.default.css +657 -0
  142. package/src/styles/duration.scss +17 -0
  143. package/src/styles/index.md +18 -0
  144. package/src/styles/is.scss +185 -0
  145. package/src/styles/ripple.scss +57 -0
  146. package/src/styles/theme.scss +16 -0
  147. package/src/styles/util.scss +78 -0
  148. package/src/styles/vars.scss +0 -0
@@ -0,0 +1,101 @@
1
+ import type { ThemePresetName, Ui0ThemePresetAppearanceConfig } from '@ui0/types'
2
+ import { hashClassName as viteHashClassName } from '@ui0/vite/css-modules'
3
+ import { describe, expect, it } from 'vitest'
4
+
5
+ import { hashClassName } from '../../generator/hash'
6
+ import type { ContractContext } from '../generator'
7
+ import createSizeGenerator from './size.generator'
8
+
9
+ const ctx = (config: Ui0ThemePresetAppearanceConfig = {}): ContractContext => ({
10
+ presetName: 'test' as ThemePresetName,
11
+ config,
12
+ settings: {},
13
+ hash: hashClassName
14
+ })
15
+
16
+ describe('createSizeGenerator - vars', () => {
17
+ it('expands control/child base heights into the height scales and derived unit scales', () => {
18
+ const g = createSizeGenerator(ctx({ size: { control: 42, child: 24 } }))
19
+ const vars = g.vars()
20
+ expect(vars.s.m).toBe('42px')
21
+ expect(vars.s.l).toBe('50px')
22
+ expect(vars.sc.m).toBe('24px')
23
+ expect(vars.uc[1]).toBe('calc(var(--0-s-m) * var(--0-s-density, 1) / 14)')
24
+ expect(vars.ucc[1]).toBe('calc(var(--0-sc-m) * var(--0-s-density, 1) / 10)')
25
+ })
26
+
27
+ it('emits the density base whenever the contract sizes anything', () => {
28
+ const g = createSizeGenerator(ctx({ size: { control: '2.5rem' } }))
29
+ expect(g.vars().s.density).toBe(1)
30
+ const empty = createSizeGenerator(ctx({}))
31
+ expect(empty.vars().s).toBeUndefined()
32
+ })
33
+
34
+ it('passes string sizes through verbatim', () => {
35
+ const g = createSizeGenerator(ctx({ size: { control: '2.5rem' } }))
36
+ expect(g.vars().s.m).toBe('2.5rem')
37
+ })
38
+
39
+ it('has no per-scheme values', () => {
40
+ const g = createSizeGenerator(ctx({ size: { control: 42 } }))
41
+ expect(g.vars('dark')).toEqual({})
42
+ expect(g.vars('light')).toEqual({})
43
+ })
44
+ })
45
+
46
+ describe('createSizeGenerator - css', () => {
47
+ it('emits a setter class per scale step pointing --0-s at the step', () => {
48
+ // the setters ship in size.inject.module.scss (sass-expanded formatting);
49
+ // flatten the whitespace to assert rule-shaped output
50
+ const flat = createSizeGenerator(ctx()).css().replace(/\s+/g, ' ')
51
+ expect(flat).toContain(`.${hashClassName('sizeXl')} { --0-s: var(--0-s-xl); }`)
52
+ expect(flat).toContain(`.${hashClassName('sizeXxxs')} { --0-s: var(--0-s-xxxs); }`)
53
+ expect(flat).toContain(`.${hashClassName('sizeM')} { --0-s: var(--0-s-m); }`)
54
+ expect(flat).toContain(`.${hashClassName('sizeCustom')} { --0-s: var(--0-s-custom); }`)
55
+ })
56
+
57
+ it('does not depend on the preset config (setters resolve through vars)', () => {
58
+ const a = createSizeGenerator(ctx({ size: { control: 42 } })).css()
59
+ const b = createSizeGenerator(ctx({})).css()
60
+ expect(a).toBe(b)
61
+ })
62
+ })
63
+
64
+ describe('createSizeGenerator - class/styles', () => {
65
+ it('maps every logical class name to the hashed dist name', () => {
66
+ const classes = createSizeGenerator(ctx()).class()
67
+ expect(Object.keys(classes)).toEqual(
68
+ expect.arrayContaining([
69
+ 'sizeXxxs',
70
+ 'sizeXxs',
71
+ 'sizeXs',
72
+ 'sizeS',
73
+ 'sizeM',
74
+ 'sizeL',
75
+ 'sizeXl',
76
+ 'sizeXxl',
77
+ 'sizeXxxl',
78
+ 'sizeCustom',
79
+ 'sized',
80
+ 'child',
81
+ 'fontSizing'
82
+ ])
83
+ )
84
+ for (const [name, hashed] of Object.entries(classes)) {
85
+ expect(hashed).toBe(hashClassName(name))
86
+ }
87
+ })
88
+
89
+ it('stays in lockstep with the @ui0/vite distiller hasher', () => {
90
+ const classes = createSizeGenerator(ctx()).class()
91
+ for (const [name, hashed] of Object.entries(classes)) {
92
+ expect(hashed).toBe(viteHashClassName(name))
93
+ }
94
+ })
95
+
96
+ it('exposes the s namespace and no inline styles', () => {
97
+ const g = createSizeGenerator(ctx())
98
+ expect(g.namespace).toBe('s')
99
+ expect(g.styles()).toEqual({})
100
+ })
101
+ })
@@ -0,0 +1,51 @@
1
+ // The size contract's generator endpoint: turns the preset's size settings
2
+ // (Ui0ThemeConfig.size: control/child base heights) into the contract's css
3
+ // vars - the --0-s-*/--0-sc-* height scales and the derived --0-uc*/--0-ucc*
4
+ // unit scales. The `size` prop setters are static - they ship in
5
+ // size.inject.module.scss (compiled + hashed at build); class() re-exports
6
+ // the registry map from size.module.css, so prop values resolve to the same
7
+ // hashed names the distiller publishes.
8
+ import type { CSSModuleClassList, VarList } from '@ui0/types'
9
+ import type { ThemeContractGenerator } from '@ui0/types'
10
+
11
+ import { renderScale, renderUnits, SCALE_RATIO } from '../../generator/scales'
12
+ import type { ContractContext, ContractFactory } from '../generator'
13
+
14
+ import sizeCss from './size.inject.module.scss'
15
+ import $size from './size.module.css'
16
+
17
+ const CONTROL_UNIT_DIVIDER = 14
18
+ const CONTROL_CHILD_UNIT_DIVIDER = 10
19
+
20
+ const sizeGenerator: ContractFactory = (ctx: ContractContext): ThemeContractGenerator => {
21
+ const { config } = ctx
22
+
23
+ function vars(): Record<string, VarList> {
24
+ const out: Record<string, VarList> = {}
25
+ const size = config.size
26
+ if (size?.control !== undefined) {
27
+ out.s = renderScale(size.control, SCALE_RATIO)
28
+ out.uc = renderUnits('uc', `calc(var(--0-s-m) * var(--0-s-density, 1) / ${CONTROL_UNIT_DIVIDER})`, 8)
29
+ }
30
+ if (size?.child !== undefined) {
31
+ out.sc = renderScale(size.child)
32
+ out.ucc = renderUnits('ucc', `calc(var(--0-sc-m) * var(--0-s-density, 1) / ${CONTROL_CHILD_UNIT_DIVIDER})`, 4)
33
+ }
34
+ // base density multiplier; the global .density-* classes flip it at
35
+ // runtime. (a per-theme density setting returns with the density contract)
36
+ if (size?.control !== undefined || size?.child !== undefined) {
37
+ out.s = { ...out.s, density: 1 }
38
+ }
39
+ return out
40
+ }
41
+
42
+ return {
43
+ namespace: 's',
44
+ vars: (scheme) => (scheme ? {} : vars()),
45
+ css: () => sizeCss,
46
+ class: (): CSSModuleClassList => ({ ...$size }),
47
+ styles: () => ({})
48
+ }
49
+ }
50
+
51
+ export default sizeGenerator
@@ -0,0 +1,12 @@
1
+ @use 'sass:string';
2
+
3
+ @value sizeXxxs, sizeXxs, sizeXs, sizeS, sizeM, sizeL, sizeXl, sizeXxl, sizeXxxl, sizeCustom from './size.module.css';
4
+
5
+ @each $step in (xxxs, xxs, xs, s, m, l, xl, xxl, xxxl) {
6
+ .size#{string.to-upper-case(string.slice($step, 1, 1))}#{string.slice($step, 2)} {
7
+ --0-s: var(--0-s-#{$step});
8
+ }
9
+ }
10
+ .sizeCustom {
11
+ --0-s: var(--0-s-custom);
12
+ }
@@ -0,0 +1,8 @@
1
+ import type { ThemeContractDeal } from '@ui0/types'
2
+ import type { InjectionKey, Ref } from 'vue'
3
+
4
+ import type { Size, SizeDensity } from './size.types'
5
+
6
+ export const SizeRefKey = Symbol('SizeRefKey') as InjectionKey<Ref<Size>>
7
+ export const SizeDensityRefKey = Symbol('DensityRefKey') as InjectionKey<Ref<SizeDensity>>
8
+ export const SizeContractKey = Symbol('SizeContractKey') as InjectionKey<ThemeContractDeal>
@@ -0,0 +1,15 @@
1
+ .sizeXl,
2
+ .sizeM,
3
+ .sizeXs,
4
+ .sizeS,
5
+ .sizeL,
6
+ .sizeXxs,
7
+ .sizeXxxs,
8
+ .sizeXxxl,
9
+ .sizeXxl,
10
+ .sizeCustom,
11
+ .sized,
12
+ .child,
13
+ .fontSizing {
14
+ /*@*/
15
+ }
@@ -0,0 +1,28 @@
1
+ /*
2
+ --0-s - own size(height)
3
+ --0-sc - size of a child component in complex component
4
+ */
5
+ @mixin use() {
6
+ --0-s: calc(var(--0-s, var(--0-s-m)) * var(--0-s-density, 1));
7
+ --0-sc: calc(var(--0-sc, var(--0-sc-m)) * var(--0-s-density, 1));
8
+ }
9
+
10
+ $size-current: calc(var(--0-s, var(--0-s-m)) * var(--0-s-density, 1));
11
+
12
+ @mixin apply {
13
+ height: var(--0-s);
14
+ }
15
+
16
+ @mixin follow {
17
+ height: var(--0-s);
18
+ }
19
+ @mixin size {
20
+ height: var(--0-s);
21
+ }
22
+ @mixin child-size {
23
+ height: var(--0-sc);
24
+ }
25
+ @mixin sizeable($h: var(--0-s, var(--0-s-m)), $hc: var(--0-sc, var(--0-sc-m))) {
26
+ --0-s: calc(#{$h} * var(--0-s-density, 1));
27
+ --0-sc: calc(#{$hc} * var(--0-s-density, 1));
28
+ }
@@ -0,0 +1,63 @@
1
+ import type { MaybeUnits, InheritValue, LiteralUnion } from '@ui0/types'
2
+
3
+ /* -------------------------------------------------------------------------- */
4
+ /* Size */
5
+ /* -------------------------------------------------------------------------- */
6
+
7
+ export type SizeXXXS = 'xxx-small' | 'xxxs'
8
+ export type SizeXXS = 'xx-small' | 'xxs'
9
+ export type SizeXS = 'x-small' | 'xs'
10
+ export type SizeS = 'small' | 's'
11
+ export type SizeM = 'medium' | 'm'
12
+ export type SizeL = 'large' | 'l'
13
+ export type SizeXL = 'x-large' | 'xl'
14
+ export type SizeXXL = 'xx-large' | 'xxl'
15
+ export type SizeXXXL = 'xxx-large' | 'xxxl'
16
+
17
+ export type Size =
18
+ | SizeXXXS
19
+ | SizeXXS
20
+ | SizeXS
21
+ | SizeS
22
+ | SizeM
23
+ | SizeL
24
+ | SizeXL
25
+ | SizeXXL
26
+ | SizeXXXL
27
+ | 'custom'
28
+ | 'smaller'
29
+ | 'larger'
30
+ | InheritValue
31
+
32
+ export type SizeDensity = LiteralUnion<'normal' | 'compact' | 'child'>
33
+
34
+ export interface SizeProps {
35
+ size?: Size
36
+ }
37
+
38
+ export interface DensityProps {
39
+ density?: SizeDensity
40
+ }
41
+
42
+ /** the size contract's settings inside a theme preset (appearance config) */
43
+ export interface SizeThemeAppearanceConfig {
44
+ /** the control's base height -> expands into the --0-s-* scale */
45
+ control?: MaybeUnits
46
+ /** a control's child (icon etc.) base height -> the --0-sc-* scale */
47
+ child?: MaybeUnits
48
+ }
49
+
50
+ /** the absolute scale steps a `size` prop can pick (long and short spellings) */
51
+ export const SizeValuesAbsolute: Size[] = ['xxxs', 'xxs', 'xs', 's', 'm', 'l', 'xl', 'xxl', 'xxxl']
52
+
53
+ // registration: the contract announces itself to the package registries
54
+ // (interface merging - no central import of the contracts anywhere)
55
+ declare module '@ui0/types/theme' {
56
+ interface Ui0ThemePresetAppearanceConfig {
57
+ size?: SizeThemeAppearanceConfig
58
+ }
59
+ interface Ui0ThemeContractSettings {
60
+ size?: boolean
61
+ }
62
+ interface Ui0ThemeContracts extends SizeProps, DensityProps {}
63
+ }
@@ -0,0 +1,17 @@
1
+ @mixin use {
2
+ // based on a input size of a component
3
+ --0c-u1: calc(var(--0c-s) / 14);
4
+ --0c-u2: calc(var(--0c-u1) * 2);
5
+ --0c-u3: calc(var(--0c-u1) * 3);
6
+ --0c-u4: calc(var(--0c-u1) * 4);
7
+ --0c-u5: calc(var(--0c-u1) * 5);
8
+ --0c-u6: calc(var(--0c-u1) * 6);
9
+ --0c-u7: calc(var(--0c-u1) * 7);
10
+ --0c-u8: calc(var(--0c-u1) * 8);
11
+
12
+ // child units (e.g. an icon inside a button)
13
+ --0c-uc1: calc(var(--0c-sc) / 10);
14
+ --0c-uc2: calc(var(--0c-uc1) * 2);
15
+ --0c-uc3: calc(var(--0c-uc1) * 3);
16
+ --0c-uc4: calc(var(--0c-uc1) * 4);
17
+ }
@@ -0,0 +1,11 @@
1
+ import type { ThemeContract } from '@ui0/types'
2
+
3
+ import { ThemeContractFlags } from '../../constants'
4
+ import { StyleContractKey } from './style.key'
5
+
6
+ export type * from './style.types'
7
+ export const style: ThemeContract = {
8
+ key: StyleContractKey,
9
+ name: 'style',
10
+ flag: ThemeContractFlags.generator
11
+ }
@@ -0,0 +1,36 @@
1
+ // The style contract's generator endpoint: passes arbitrary css through from
2
+ // the preset config - `style.vars` become `--0-style-*` custom properties on
3
+ // the theme block, `style.raw` lands as plain declarations. No classes of its
4
+ // own.
5
+ import type { CSSModuleClassList, StyleList, VarList } from '@ui0/types'
6
+ import type { ThemeContractGenerator } from '@ui0/types'
7
+
8
+ import type { ContractFactory } from '../generator'
9
+
10
+ const styleGenerator: ContractFactory = (ctx): ThemeContractGenerator => {
11
+ const { config } = ctx
12
+
13
+ function vars(): Record<string, VarList> {
14
+ const style = config.style
15
+ if (!style?.vars) return {}
16
+ return {
17
+ style: Object.fromEntries(Object.entries(style.vars))
18
+ }
19
+ }
20
+
21
+ function styles(): StyleList {
22
+ const style = config.style
23
+ if (!style?.raw) return {}
24
+ return { ...style.raw }
25
+ }
26
+
27
+ return {
28
+ namespace: 'style',
29
+ vars: (scheme) => (scheme ? {} : vars()),
30
+ css: () => '',
31
+ class: (): CSSModuleClassList => ({}),
32
+ styles: (scheme) => (scheme ? {} : styles())
33
+ }
34
+ }
35
+
36
+ export default styleGenerator
@@ -0,0 +1,4 @@
1
+ import type { ThemeContractDeal } from '@ui0/types'
2
+ import type { InjectionKey } from 'vue'
3
+
4
+ export const StyleContractKey = Symbol('StyleContractKey') as InjectionKey<ThemeContractDeal>
@@ -0,0 +1,16 @@
1
+ import type { StyleList } from '@ui0/types'
2
+
3
+ declare module '@ui0/types/theme' {
4
+ interface Ui0ThemePresetAppearanceConfig {
5
+ style?: {
6
+ vars?: StyleList
7
+ raw?: StyleList
8
+ }
9
+ }
10
+ interface Ui0ThemeContractSettings {
11
+ style?: boolean
12
+ }
13
+ interface Ui0ThemeContracts {
14
+ style?: StyleList
15
+ }
16
+ }
@@ -0,0 +1,26 @@
1
+ // The typography contract's registry entry, generated from
2
+ // packages/templates/contract. Wiring left (see the generator output):
3
+ // 1. add `typography` to src/contracts/index.ts (next to round/size/...)
4
+ // 2. add typographyGenerator to src/generator.ts (contractGenerators)
5
+ import { ThemeContractFlags } from '../../constants'
6
+ import type { ThemeContract } from '../../types'
7
+ import { typographyDeal } from './typography.contract'
8
+ import { TypographyContractKey, TypographyRefKey } from './typography.keys'
9
+ import type { TypographyProps } from './typography.types'
10
+
11
+ export { default as $style } from './typography.module.css'
12
+ export type * from './typography.types'
13
+ export * from './typography.keys'
14
+
15
+ export const TypographyPropsKeys: ReadonlyArray<keyof TypographyProps> = [
16
+ 'typography'
17
+ ]
18
+
19
+ export const typography: ThemeContract = {
20
+ key: TypographyContractKey,
21
+ name: 'typography',
22
+ ref: TypographyRefKey,
23
+ deal: typographyDeal,
24
+ flag: ThemeContractFlags.dealer + ThemeContractFlags.generator,
25
+ props: TypographyPropsKeys
26
+ }
@@ -0,0 +1,52 @@
1
+ // The typography contract's processing endpoint: closes over the provider and
2
+ // returns the deal that maps the `typography` prop onto classes/styles at
3
+ // runtime, resolving `inherit` against the provided context ref.
4
+ import type { ClassList, CSSModuleClassList } from '@ui0/types'
5
+ import type { Ref } from 'vue'
6
+
7
+ import { EMPTY_OBJ } from '../../constants'
8
+ import type { ContractProvider, ThemeContractDeal } from '../../types'
9
+ import { mergeCssModulesStyles } from '@ui0/util'
10
+
11
+ import type { TypographyProps } from './typography.types'
12
+ import $typography from './typography.module.css'
13
+
14
+ // the prop -> class wiring: the prop value IS the logical class name from the
15
+ // registry (e.g. `typography="fw700"`), resolved to its hashed form from the
16
+ // module map (merged with the component's own $style)
17
+ function typographyClasses(
18
+ props: TypographyProps,
19
+ styles?: CSSModuleClassList
20
+ ): ClassList {
21
+ const $ = mergeCssModulesStyles($typography, styles)
22
+ const out: ClassList = []
23
+ if (props.typography && $[props.typography]) out.push($[props.typography])
24
+ return out
25
+ }
26
+
27
+ export function typographyDeal(instance: ContractProvider): ThemeContractDeal {
28
+ const props = instance.props
29
+
30
+ return {
31
+ classes: () => {
32
+ if (!props.typography) return instance.inject([])
33
+
34
+ if (props.typography === 'inherit') {
35
+ const ctx = instance.context as Record<
36
+ string,
37
+ Ref<any> | undefined
38
+ > | null
39
+ if (ctx?.typography) {
40
+ return instance.inject(
41
+ typographyClasses({ typography: ctx.typography.value }, instance.$styles)
42
+ )
43
+ }
44
+ }
45
+
46
+ return instance.inject(
47
+ typographyClasses(props as TypographyProps, instance.$styles)
48
+ )
49
+ },
50
+ styles: () => instance.inject(EMPTY_OBJ)
51
+ }
52
+ }
@@ -0,0 +1,48 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { hashClassName } from '../../generator/hash'
4
+ import type { ThemePresetName } from '../../types'
5
+ import type { ContractContext } from '../generator'
6
+ import createTypographyGenerator from './typography.generator'
7
+
8
+ const ctx = (config = {}): ContractContext => ({
9
+ presetName: 'test' as ThemePresetName,
10
+ config,
11
+ settings: {},
12
+ hash: hashClassName
13
+ })
14
+
15
+ describe('createTypographyGenerator', () => {
16
+ it('emits a var for the configured base', () => {
17
+ const vars = createTypographyGenerator(
18
+ ctx({ typography: { base: '4px' } })
19
+ ).vars()
20
+ expect(vars.typography.base).toBe('4px')
21
+ })
22
+
23
+ it('emits nothing without config', () => {
24
+ expect(createTypographyGenerator(ctx()).vars()).toEqual({})
25
+ })
26
+
27
+ it('maps the registry class names onto the hashed dist names', () => {
28
+ const classes = createTypographyGenerator(ctx()).class()
29
+ expect(classes.fw100).toBe(hashClassName('fw100'))
30
+ expect(classes['tt-uppercase']).toBe(hashClassName('tt-uppercase'))
31
+ expect(classes['tw-stable']).toBe(hashClassName('tw-stable'))
32
+ expect(Object.keys(classes)).toHaveLength(32)
33
+ })
34
+
35
+ it('ships the contract css from the inject module, hashed', () => {
36
+ const css = createTypographyGenerator(ctx()).css()
37
+ expect(css).toContain(`.${hashClassName('fw700')} { font-weight: 700 }`)
38
+ expect(css).toContain(`.${hashClassName('ta-center')} { text-align: center }`)
39
+ expect(css).not.toContain('@value')
40
+ expect(css).not.toContain('.fw700')
41
+ })
42
+
43
+ it('has no per-scheme values', () => {
44
+ const g = createTypographyGenerator(ctx({ typography: { base: '4px' } }))
45
+ expect(g.vars('dark')).toEqual({})
46
+ expect(g.namespace).toBe('t')
47
+ })
48
+ })
@@ -0,0 +1,44 @@
1
+ // The typography contract's generator endpoint: turns the contract's slice of
2
+ // the appearance config (TypographyThemeAppearanceConfig) into css vars and
3
+ // ships the contract's own static css (the font-weight / text-transform /
4
+ // text-align / text-orientation / text-wrap utility setters). The setter css
5
+ // lives in typography.inject.module.css - the ui0 css-modules pipeline
6
+ // compiles it and hashes the selectors at build; class() re-exports the
7
+ // registry map from typography.module.css, so logical names resolve to the
8
+ // same hashes everywhere.
9
+ import type { CSSModuleClassList, ThemeContractGenerator, VarList } from '@ui0/types'
10
+ import { toUnits, tryToUnits } from '@ui0/util'
11
+
12
+ import type { ContractContext, ContractFactory } from '../generator'
13
+
14
+ import typographyCss from './typography.inject.module.css'
15
+ import $typography from './typography.module.css'
16
+
17
+ const typographyGenerator: ContractFactory = (ctx: ContractContext): ThemeContractGenerator => {
18
+ function vars(): Record<string, VarList> {
19
+ // after registration (see typography.types.ts) this reads
20
+ // `config.typography`; typed loosely until the contract is named.
21
+
22
+ if (ctx.settings.typography) {
23
+ const { headingRatio, fontSizeHeading, fontSize } = ctx.settings.typography
24
+ return {
25
+ typo: {
26
+ fs: tryToUnits(fontSize),
27
+ 'h-ratio': headingRatio,
28
+ 'h-fs': toUnits(fontSizeHeading) || tryToUnits(fontSize)
29
+ }
30
+ }
31
+ }
32
+ return {}
33
+ }
34
+
35
+ return {
36
+ namespace: 't',
37
+ vars: (scheme) => (scheme ? {} : vars()),
38
+ css: () => typographyCss,
39
+ class: (): CSSModuleClassList => ({ ...$typography }),
40
+ styles: () => ({})
41
+ }
42
+ }
43
+
44
+ export default typographyGenerator
@@ -0,0 +1,54 @@
1
+ @value fw100, fw200, fw300, fw400, fw500, fw600, fw700, fw800, fw900 from './typography.module.css';
2
+ @value tt-uppercase, tt-lowercase, tt-capitalize, tt-none, tt-full, tt-full-size-kana from './typography.module.css';
3
+ @value ta-start, ta-end, ta-center, ta-left, ta-right, ta-justify, ta-match-parent from './typography.module.css';
4
+ @value to-mixed, to-sideways, to-sideways-right, to-use-glyph-orientation, to-upright from './typography.module.css';
5
+ @value tw-nowrap, tw-wrap, tw-balance, tw-pretty, tw-stable from './typography.module.css';
6
+
7
+ .fw100 { font-weight: 100 }
8
+ .fw200 { font-weight: 200 }
9
+ .fw300 { font-weight: 300 }
10
+ .fw400 { font-weight: 400 }
11
+ .fw500 { font-weight: 500 }
12
+ .fw600 { font-weight: 600 }
13
+ .fw700 { font-weight: 700 }
14
+ .fw800 { font-weight: 800 }
15
+ .fw900 { font-weight: 900 }
16
+
17
+ .tt-uppercase { text-transform: uppercase }
18
+ .tt-lowercase { text-transform: lowercase }
19
+ .tt-capitalize { text-transform: capitalize }
20
+ .tt-none { text-transform: none }
21
+ .tt-full { text-transform: full-width }
22
+ .tt-full-size-kana { text-transform: full-size-kana }
23
+
24
+ .ta-start { text-align: start }
25
+ .ta-end { text-align: end }
26
+ .ta-center { text-align: center }
27
+ .ta-left { text-align: left }
28
+ .ta-right { text-align: right }
29
+ .ta-justify { text-align: justify }
30
+ .ta-match-parent { text-align: match-parent }
31
+
32
+ .to-mixed { text-orientation: mixed }
33
+ .to-sideways { text-orientation: sideways }
34
+ .to-sideways-right { text-orientation: sideways-right }
35
+ .to-use-glyph-orientation { text-orientation: use-glyph-orientation }
36
+ .to-upright { text-orientation: upright }
37
+
38
+ .tw-nowrap { text-wrap: nowrap }
39
+ .tw-wrap { text-wrap: wrap }
40
+ .tw-balance { text-wrap: balance }
41
+ .tw-pretty { text-wrap: pretty }
42
+ .tw-stable { text-wrap: stable }
43
+ h1, h2, h3, h4, h5, h6 {
44
+ --0-typo-step: 0.25rem; /* шаг (длина) */
45
+ font-size: calc(var(--0-typo-h-fs, var(--0-typo-fs, 1rem)) + var(--0-typo-step) * var(--0-typo-x));
46
+ line-height: calc(1 + 1 / var(--0-typo-x));
47
+
48
+ }
49
+ h1 { --0-typo-x: 6; }
50
+ h2 { --0-typo-x: 5; }
51
+ h3 { --0-typo-x: 4; }
52
+ h4 { --0-typo-x: 3; }
53
+ h5 { --0-typo-x: 2; }
54
+ h6 { --0-typo-x: 1; }
@@ -0,0 +1,12 @@
1
+ import type { InjectionKey, Ref } from 'vue'
2
+
3
+ import type { ThemeContract } from '../../types'
4
+ import type { TypographyProp } from './typography.types'
5
+
6
+ /** context key the deal resolves `inherit` against (see useThemeContract) */
7
+ export const TypographyRefKey = Symbol('TypographyRefKey') as InjectionKey<
8
+ Ref<TypographyProp | undefined>
9
+ >
10
+ export const TypographyContractKey = Symbol(
11
+ 'TypographyContractKey'
12
+ ) as InjectionKey<ThemeContract>
@@ -0,0 +1,36 @@
1
+
2
+ .fw100,
3
+ .fw200,
4
+ .fw300,
5
+ .fw400,
6
+ .fw500,
7
+ .fw600,
8
+ .fw700,
9
+ .fw800,
10
+ .fw900,
11
+ .tt-uppercase,
12
+ .tt-lowercase,
13
+ .tt-capitalize,
14
+ .tt-none,
15
+ .tt-full,
16
+ .tt-full-size-kana,
17
+ .ta-center,
18
+ .ta-end,
19
+ .ta-justify,
20
+ .ta-left,
21
+ .ta-match-parent,
22
+ .ta-right,
23
+ .ta-start,
24
+ .to-mixed,
25
+ .to-sideways,
26
+ .to-sideways-right,
27
+ .to-use-glyph-orientation,
28
+ .to-upright,
29
+ .tw-nowrap,
30
+ .tw-wrap,
31
+ .tw-balance,
32
+ .tw-pretty,
33
+ .tw-stable,
34
+ {
35
+ /*@shared*/
36
+ }
@@ -0,0 +1,21 @@
1
+ // Component-namespace wiring for the typography contract: the generator emits
2
+ // `--0-typography-base` on the theme blocks; this mixin mirrors it into the
3
+ // component namespace so a component can consume (and locally override) it.
4
+ @mixin init() {
5
+ --0-typo-base: 1.2;
6
+
7
+ code {
8
+ //background-color: rgba(var(--r-c-foreground-v), 0.2);
9
+ border-radius: 0;
10
+ }
11
+ h1, h2, h3, h4, h5, h6 {
12
+ font-size: calc(var(--0-typo-h-fs, var(--0-typo-fs)) * var(--0-typo-h-ratio, 1) * var(--0-typo-x, 1));
13
+ }
14
+ h1 { --0-typo-x: 6; }
15
+ h2 { --0-typo-x: 5; }
16
+ h3 { --0-typo-x: 4; }
17
+ h4 { --0-typo-x: 3; }
18
+ h5 { --0-typo-x: 2; }
19
+ h6 { --0-typo-x: 1; }
20
+ body { font-size: var(--0-typo-font-size); }
21
+ }