ux4g-components-web 1.4.0 → 1.5.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 (124) hide show
  1. package/README.md +76 -0
  2. package/dist/__tests__/css-bundle.integration.test.d.ts +11 -0
  3. package/dist/__tests__/css-bundle.integration.test.js +1102 -0
  4. package/dist/__tests__/css-bundle.phase10.property.test.d.ts +9 -0
  5. package/dist/__tests__/css-bundle.phase10.property.test.js +64 -0
  6. package/dist/__tests__/css-bundle.phase5.property.test.d.ts +9 -0
  7. package/dist/__tests__/css-bundle.phase5.property.test.js +126 -0
  8. package/dist/__tests__/css-bundle.phase6.property.test.d.ts +9 -0
  9. package/dist/__tests__/css-bundle.phase6.property.test.js +73 -0
  10. package/dist/__tests__/css-bundle.phase7.property.test.d.ts +9 -0
  11. package/dist/__tests__/css-bundle.phase7.property.test.js +76 -0
  12. package/dist/__tests__/css-bundle.phase8.property.test.d.ts +9 -0
  13. package/dist/__tests__/css-bundle.phase8.property.test.js +67 -0
  14. package/dist/__tests__/css-bundle.phase9.property.test.d.ts +9 -0
  15. package/dist/__tests__/css-bundle.phase9.property.test.js +93 -0
  16. package/dist/__tests__/css-bundle.property.test.d.ts +14 -0
  17. package/dist/__tests__/css-bundle.property.test.js +393 -0
  18. package/dist/__tests__/dom-generators.determinism.property.test.d.ts +1 -0
  19. package/dist/__tests__/dom-generators.determinism.property.test.js +71 -0
  20. package/dist/__tests__/dom-generators.id.property.test.d.ts +1 -0
  21. package/dist/__tests__/dom-generators.id.property.test.js +99 -0
  22. package/dist/__tests__/dom-generators.otp.property.test.d.ts +1 -0
  23. package/dist/__tests__/dom-generators.property.test.d.ts +1 -0
  24. package/dist/__tests__/dom-generators.property.test.js +205 -0
  25. package/dist/__tests__/dom-generators.states.property.test.d.ts +1 -0
  26. package/dist/__tests__/dom-generators.table.property.test.d.ts +1 -0
  27. package/dist/__tests__/dom-generators.tier1.property.test.d.ts +1 -0
  28. package/dist/__tests__/dom-generators.tier1.property.test.js +403 -0
  29. package/dist/__tests__/dom-generators.validation.property.test.d.ts +1 -0
  30. package/dist/__tests__/dom-generators.validation.property.test.js +327 -0
  31. package/dist/__tests__/megamenu.classbuilder.property.test.d.ts +1 -0
  32. package/dist/__tests__/megamenu.classbuilder.property.test.js +88 -0
  33. package/dist/__tests__/smoke.test.d.ts +1 -0
  34. package/dist/__tests__/smoke.test.js +65 -0
  35. package/dist/__tests__/types.phase10.property.test.d.ts +1 -0
  36. package/dist/__tests__/types.phase10.property.test.js +166 -0
  37. package/dist/__tests__/types.phase10.test.d.ts +1 -0
  38. package/dist/__tests__/types.phase10.test.js +76 -0
  39. package/dist/__tests__/types.phase3.property.test.d.ts +1 -0
  40. package/dist/__tests__/types.phase3.property.test.js +83 -0
  41. package/dist/__tests__/types.phase3.test.d.ts +1 -0
  42. package/dist/__tests__/types.phase3.test.js +76 -0
  43. package/dist/__tests__/types.phase4.property.test.d.ts +1 -0
  44. package/dist/__tests__/types.phase4.property.test.js +119 -0
  45. package/dist/__tests__/types.phase4.test.d.ts +1 -0
  46. package/dist/__tests__/types.phase4.test.js +70 -0
  47. package/dist/__tests__/types.phase5.property.test.d.ts +1 -0
  48. package/dist/__tests__/types.phase5.property.test.js +120 -0
  49. package/dist/__tests__/types.phase5.test.d.ts +1 -0
  50. package/dist/__tests__/types.phase5.test.js +64 -0
  51. package/dist/__tests__/types.phase6.property.test.d.ts +1 -0
  52. package/dist/__tests__/types.phase6.property.test.js +189 -0
  53. package/dist/__tests__/types.phase6.test.d.ts +1 -0
  54. package/dist/__tests__/types.phase6.test.js +121 -0
  55. package/dist/__tests__/types.phase7.property.test.d.ts +1 -0
  56. package/dist/__tests__/types.phase7.property.test.js +217 -0
  57. package/dist/__tests__/types.phase7.test.d.ts +1 -0
  58. package/dist/__tests__/types.phase7.test.js +106 -0
  59. package/dist/__tests__/types.phase8.property.test.d.ts +1 -0
  60. package/dist/__tests__/types.phase8.property.test.js +224 -0
  61. package/dist/__tests__/types.phase8.test.d.ts +1 -0
  62. package/dist/__tests__/types.phase8.test.js +114 -0
  63. package/dist/__tests__/types.phase9.property.test.d.ts +1 -0
  64. package/dist/__tests__/types.phase9.property.test.js +347 -0
  65. package/dist/__tests__/types.phase9.test.d.ts +1 -0
  66. package/dist/__tests__/types.phase9.test.js +226 -0
  67. package/dist/__tests__/types.restructure.property.test.d.ts +1 -0
  68. package/dist/__tests__/types.restructure.property.test.js +76 -0
  69. package/dist/__tests__/types.test.d.ts +1 -0
  70. package/dist/__tests__/types.test.js +175 -0
  71. package/dist/dom-generators/accordion.d.ts +23 -0
  72. package/dist/dom-generators/avatar.d.ts +19 -0
  73. package/dist/dom-generators/carousel.d.ts +20 -0
  74. package/dist/dom-generators/chip.d.ts +18 -0
  75. package/dist/dom-generators/combobox.d.ts +28 -0
  76. package/dist/dom-generators/date-picker.d.ts +19 -0
  77. package/dist/dom-generators/dom-generators/accordion.d.ts +21 -0
  78. package/dist/dom-generators/dom-generators/avatar.d.ts +17 -0
  79. package/dist/dom-generators/dom-generators/carousel.d.ts +19 -0
  80. package/dist/dom-generators/dom-generators/chip.d.ts +16 -0
  81. package/dist/dom-generators/dom-generators/combobox.d.ts +26 -0
  82. package/dist/dom-generators/dom-generators/date-picker.d.ts +18 -0
  83. package/dist/dom-generators/dom-generators/drawer.d.ts +17 -0
  84. package/dist/dom-generators/dom-generators/dropdown.d.ts +26 -0
  85. package/dist/dom-generators/dom-generators/file-upload.d.ts +20 -0
  86. package/dist/dom-generators/dom-generators/id-generator.d.ts +9 -0
  87. package/dist/dom-generators/dom-generators/index.d.ts +27 -0
  88. package/dist/dom-generators/dom-generators/modal.d.ts +19 -0
  89. package/dist/dom-generators/dom-generators/otp.d.ts +16 -0
  90. package/dist/dom-generators/dom-generators/popover.d.ts +17 -0
  91. package/dist/dom-generators/dom-generators/progress.d.ts +16 -0
  92. package/dist/dom-generators/dom-generators/search.d.ts +20 -0
  93. package/dist/dom-generators/dom-generators/stepper.d.ts +21 -0
  94. package/dist/dom-generators/dom-generators/table.d.ts +23 -0
  95. package/dist/dom-generators/dom-generators/tabs.d.ts +21 -0
  96. package/dist/dom-generators/dom-generators/time-picker.d.ts +18 -0
  97. package/dist/dom-generators/dom-generators/tooltip.d.ts +17 -0
  98. package/dist/dom-generators/dom-generators/types.d.ts +27 -0
  99. package/dist/dom-generators/dom-generators/validate.d.ts +20 -0
  100. package/dist/dom-generators/drawer.d.ts +19 -0
  101. package/dist/dom-generators/dropdown.d.ts +28 -0
  102. package/dist/dom-generators/file-upload.d.ts +22 -0
  103. package/dist/dom-generators/id-generator.d.ts +9 -0
  104. package/dist/dom-generators/index.bundled.d.ts +654 -0
  105. package/dist/dom-generators/index.cjs +2029 -0
  106. package/dist/dom-generators/index.d.ts +27 -0
  107. package/dist/dom-generators/index.mjs +2001 -0
  108. package/dist/dom-generators/modal.d.ts +21 -0
  109. package/dist/dom-generators/otp.d.ts +18 -0
  110. package/dist/dom-generators/popover.d.ts +19 -0
  111. package/dist/dom-generators/progress.d.ts +18 -0
  112. package/dist/dom-generators/search.d.ts +22 -0
  113. package/dist/dom-generators/stepper.d.ts +23 -0
  114. package/dist/dom-generators/table.d.ts +25 -0
  115. package/dist/dom-generators/tabs.d.ts +23 -0
  116. package/dist/dom-generators/time-picker.d.ts +19 -0
  117. package/dist/dom-generators/tooltip.d.ts +19 -0
  118. package/dist/dom-generators/types.d.ts +155 -0
  119. package/dist/dom-generators/validate.d.ts +20 -0
  120. package/dist/runtime/bootstrap.js +59 -0
  121. package/dist/runtime/index.js +55 -0
  122. package/dist/types.d.ts +155 -0
  123. package/dist/types.js +552 -0
  124. package/package.json +12 -2
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Property-based tests for Phase 6 build functions
3
+ *
4
+ * Property 1: List class string contains all required tokens and has no duplicates
5
+ * Property 2: Dropdown class string contains all required tokens and correctly toggles is-open
6
+ * Property 3: Combobox class string contains all required tokens and correctly toggles is-open
7
+ * Property 4: Modal backdrop class string contains required tokens and correctly toggles blur and is-open
8
+ * Property 5: Modal box class string contains required tokens and correctly toggles center-content
9
+ * Property 6: Inline alert class string contains required tokens and applies mutually exclusive layout modifiers
10
+ * Property 7: Context-alert class string uses ux4g-context-alert as base and does not include standalone ux4g-alert
11
+ * Property 8: Alert container class string contains required tokens for all positions
12
+ * Property 9: Search container class string contains required tokens for all sizes, and extra param is always appended
13
+ */
14
+ import * as fc from 'fast-check';
15
+ import { buildListClasses, buildDropdownClasses, buildComboboxClasses, buildModalBackdropClasses, buildModalBoxClasses, buildAlertClasses, buildContextAlertClasses, buildAlertContainerClasses, buildSearchContainerClasses, } from '../../src/types';
16
+ /**
17
+ * Property 1: List class string contains all required tokens and has no duplicates
18
+ * Tag: Feature: ux4g-phase6-components, Property 1
19
+ * Validates: Requirements 12.1, 12.2
20
+ */
21
+ describe('Property 1: List class string contains all required tokens and has no duplicates', () => {
22
+ it('Feature: ux4g-phase6-components, Property 1', () => {
23
+ fc.assert(fc.property(fc.constantFrom('default', 'error', 'success', 'warning'), fc.constantFrom('s', 'm', 'l', 'xl'), (variant, size) => {
24
+ const result = buildListClasses(variant, size);
25
+ const tokens = result.split(' ');
26
+ const hasBase = tokens.includes('ux4g-list');
27
+ const hasVariant = tokens.includes(`ux4g-list-${variant}`);
28
+ const hasSize = tokens.includes(`ux4g-list-${size}`);
29
+ const noDuplicates = tokens.length === new Set(tokens).size;
30
+ return hasBase && hasVariant && hasSize && noDuplicates;
31
+ }), { numRuns: 100 });
32
+ });
33
+ });
34
+ /**
35
+ * Property 2: Dropdown class string contains all required tokens and correctly toggles is-open
36
+ * Tag: Feature: ux4g-phase6-components, Property 2
37
+ * Validates: Requirements 12.4, 12.5
38
+ */
39
+ describe('Property 2: Dropdown class string contains all required tokens and correctly toggles is-open', () => {
40
+ it('Feature: ux4g-phase6-components, Property 2', () => {
41
+ fc.assert(fc.property(fc.constantFrom('selection', 'button', 'overflow'), fc.constantFrom('single', 'multi'), fc.constantFrom('sm', 'md', 'lg'), fc.constantFrom('default', 'error', 'success', 'warning'), fc.boolean(), (type, mode, size, state, open) => {
42
+ const result = buildDropdownClasses(type, mode, size, state, open);
43
+ const tokens = result.split(' ');
44
+ const hasBase = tokens.includes('ux4g-dropdown');
45
+ const hasType = tokens.includes(`ux4g-dropdown-${type}`);
46
+ const hasMode = tokens.includes(`ux4g-dropdown-${mode}`);
47
+ const hasSize = tokens.includes(`ux4g-dropdown-${size}`);
48
+ const hasState = tokens.includes(`ux4g-dropdown-${state}`);
49
+ const openCorrect = open ? tokens.includes('is-open') : !tokens.includes('is-open');
50
+ return hasBase && hasType && hasMode && hasSize && hasState && openCorrect;
51
+ }), { numRuns: 100 });
52
+ });
53
+ });
54
+ /**
55
+ * Property 3: Combobox class string contains all required tokens and correctly toggles is-open
56
+ * Tag: Feature: ux4g-phase6-components, Property 3
57
+ * Validates: Requirements 12.6, 12.7
58
+ */
59
+ describe('Property 3: Combobox class string contains all required tokens and correctly toggles is-open', () => {
60
+ it('Feature: ux4g-phase6-components, Property 3', () => {
61
+ fc.assert(fc.property(fc.constantFrom('single', 'multi'), fc.constantFrom('sm', 'md', 'lg'), fc.constantFrom('default', 'error', 'success', 'warning'), fc.boolean(), (type, size, state, open) => {
62
+ const result = buildComboboxClasses(type, size, state, open);
63
+ const tokens = result.split(' ');
64
+ const hasBase = tokens.includes('ux4g-combobox');
65
+ const hasType = tokens.includes(`ux4g-combobox-${type}`);
66
+ const hasSize = tokens.includes(`ux4g-combobox-${size}`);
67
+ const hasState = tokens.includes(`ux4g-combobox-${state}`);
68
+ const openCorrect = open ? tokens.includes('is-open') : !tokens.includes('is-open');
69
+ return hasBase && hasType && hasSize && hasState && openCorrect;
70
+ }), { numRuns: 100 });
71
+ });
72
+ });
73
+ /**
74
+ * Property 4: Modal backdrop class string contains required tokens and correctly toggles blur and is-open
75
+ * Tag: Feature: ux4g-phase6-components, Property 4
76
+ * Validates: Requirements 12.8, 12.9, 12.10
77
+ */
78
+ describe('Property 4: Modal backdrop class string contains required tokens and correctly toggles blur and is-open', () => {
79
+ it('Feature: ux4g-phase6-components, Property 4', () => {
80
+ fc.assert(fc.property(fc.constantFrom('25', '50', '75'), fc.boolean(), fc.boolean(), (opacity, blur, open) => {
81
+ const result = buildModalBackdropClasses(opacity, blur, open);
82
+ const tokens = result.split(' ');
83
+ const hasBase = tokens.includes('ux4g-modal-backdrop');
84
+ const hasOpacity = tokens.includes(`ux4g-modal-backdrop-${opacity}`);
85
+ const blurCorrect = blur ? tokens.includes('ux4g-modal-backdrop-blur') : !tokens.includes('ux4g-modal-backdrop-blur');
86
+ const openCorrect = open ? tokens.includes('is-open') : !tokens.includes('is-open');
87
+ return hasBase && hasOpacity && blurCorrect && openCorrect;
88
+ }), { numRuns: 100 });
89
+ });
90
+ });
91
+ /**
92
+ * Property 5: Modal box class string contains required tokens and correctly toggles center-content
93
+ * Tag: Feature: ux4g-phase6-components, Property 5
94
+ * Validates: Requirements 12.11, 12.12
95
+ */
96
+ describe('Property 5: Modal box class string contains required tokens and correctly toggles center-content', () => {
97
+ it('Feature: ux4g-phase6-components, Property 5', () => {
98
+ fc.assert(fc.property(fc.constantFrom('s', 'm', 'l'), fc.boolean(), (size, centerContent) => {
99
+ const result = buildModalBoxClasses(size, centerContent);
100
+ const tokens = result.split(' ');
101
+ const hasBase = tokens.includes('ux4g-modal-box');
102
+ const hasSize = tokens.includes(`ux4g-modal-${size}`);
103
+ const centerCorrect = centerContent
104
+ ? tokens.includes('ux4g-modal-center-content')
105
+ : !tokens.includes('ux4g-modal-center-content');
106
+ return hasBase && hasSize && centerCorrect;
107
+ }), { numRuns: 100 });
108
+ });
109
+ });
110
+ /**
111
+ * Property 6: Inline alert class string contains required tokens and applies mutually exclusive layout modifiers
112
+ * Tag: Feature: ux4g-phase6-components, Property 6
113
+ * Validates: Requirements 12.13, 12.14
114
+ */
115
+ describe('Property 6: Inline alert class string contains required tokens and applies mutually exclusive layout modifiers', () => {
116
+ it('Feature: ux4g-phase6-components, Property 6', () => {
117
+ fc.assert(fc.property(fc.constantFrom('info', 'success', 'warning', 'error'), fc.constantFrom('fluid', 'center', 'wide'), (variant, layout) => {
118
+ const result = buildAlertClasses(variant, layout);
119
+ const tokens = result.split(' ');
120
+ const hasBase = tokens.includes('ux4g-alert');
121
+ const hasVariant = tokens.includes(`ux4g-alert-${variant}`);
122
+ let layoutCorrect;
123
+ if (layout === 'center') {
124
+ layoutCorrect = tokens.includes('ux4g-alert-center') && !tokens.includes('ux4g-alert-wide');
125
+ }
126
+ else if (layout === 'wide') {
127
+ layoutCorrect = tokens.includes('ux4g-alert-wide') && !tokens.includes('ux4g-alert-center');
128
+ }
129
+ else {
130
+ // fluid — neither modifier present
131
+ layoutCorrect = !tokens.includes('ux4g-alert-center') && !tokens.includes('ux4g-alert-wide');
132
+ }
133
+ return hasBase && hasVariant && layoutCorrect;
134
+ }), { numRuns: 100 });
135
+ });
136
+ });
137
+ /**
138
+ * Property 7: Context-alert class string uses ux4g-context-alert as base and does not include standalone ux4g-alert
139
+ * Tag: Feature: ux4g-phase6-components, Property 7
140
+ * Validates: Requirements 12.15
141
+ */
142
+ describe('Property 7: Context-alert class string uses ux4g-context-alert as base and does not include standalone ux4g-alert', () => {
143
+ it('Feature: ux4g-phase6-components, Property 7', () => {
144
+ fc.assert(fc.property(fc.constantFrom('info', 'success', 'warning', 'error'), (variant) => {
145
+ const result = buildContextAlertClasses(variant);
146
+ const tokens = result.split(' ');
147
+ const hasContextBase = tokens.includes('ux4g-context-alert');
148
+ const hasVariant = tokens.includes(`ux4g-alert-${variant}`);
149
+ // 'ux4g-alert' must NOT appear as a standalone token (exact match)
150
+ const noStandaloneAlert = !tokens.includes('ux4g-alert');
151
+ return hasContextBase && hasVariant && noStandaloneAlert;
152
+ }), { numRuns: 100 });
153
+ });
154
+ });
155
+ /**
156
+ * Property 8: Alert container class string contains required tokens for all positions
157
+ * Tag: Feature: ux4g-phase6-components, Property 8
158
+ * Validates: Requirements 12.16
159
+ */
160
+ describe('Property 8: Alert container class string contains required tokens for all positions', () => {
161
+ it('Feature: ux4g-phase6-components, Property 8', () => {
162
+ fc.assert(fc.property(fc.constantFrom('top-left', 'top-right', 'bottom-left', 'bottom-right'), (position) => {
163
+ const result = buildAlertContainerClasses(position);
164
+ const tokens = result.split(' ');
165
+ const hasBase = tokens.includes('ux4g-alert-container');
166
+ const hasPosition = tokens.includes(`ux4g-alert-${position}`);
167
+ return hasBase && hasPosition;
168
+ }), { numRuns: 100 });
169
+ });
170
+ });
171
+ /**
172
+ * Property 9: Search container class string contains required tokens for all sizes, and extra param is always appended
173
+ * Tag: Feature: ux4g-phase6-components, Property 9
174
+ * Validates: Requirements 12.17, 12.18
175
+ */
176
+ describe('Property 9: Search container class string contains required tokens for all sizes, and extra param is always appended', () => {
177
+ it('Feature: ux4g-phase6-components, Property 9', () => {
178
+ fc.assert(fc.property(fc.constantFrom('s', 'm', 'lg'), fc.option(fc.stringMatching(/^[a-z][a-z0-9-]*$/), { nil: undefined }), (size, extra) => {
179
+ const result = buildSearchContainerClasses(size, extra);
180
+ const tokens = result.split(' ');
181
+ const hasBase = tokens.includes('ux4g-search-container');
182
+ const hasSize = tokens.includes(`ux4g-search-${size}`);
183
+ const extraCorrect = extra !== undefined
184
+ ? tokens.includes(extra) && tokens.length === new Set(tokens).size
185
+ : true;
186
+ return hasBase && hasSize && extraCorrect;
187
+ }), { numRuns: 100 });
188
+ });
189
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,121 @@
1
+ import { buildListClasses, buildDropdownClasses, buildComboboxClasses, buildModalBackdropClasses, buildModalBoxClasses, buildAlertClasses, buildContextAlertClasses, buildAlertContainerClasses, buildSearchContainerClasses, } from '../../src/types';
2
+ // ── buildListClasses ──────────────────────────────────────────────────────────
3
+ // Requirements: 4.3
4
+ describe('buildListClasses', () => {
5
+ it("variant='default' size='m' → base + variant + size", () => {
6
+ expect(buildListClasses('default', 'm')).toBe('ux4g-list ux4g-list-default ux4g-list-m');
7
+ });
8
+ it("variant='error' size='s' → base + variant + size", () => {
9
+ expect(buildListClasses('error', 's')).toBe('ux4g-list ux4g-list-error ux4g-list-s');
10
+ });
11
+ it("variant='success' size='xl' with extra → appends extra class", () => {
12
+ expect(buildListClasses('success', 'xl', 'my-list')).toBe('ux4g-list ux4g-list-success ux4g-list-xl my-list');
13
+ });
14
+ });
15
+ // ── buildDropdownClasses ──────────────────────────────────────────────────────
16
+ // Requirements: 4.8
17
+ describe('buildDropdownClasses', () => {
18
+ it("type='selection' mode='single' size='md' state='default' → all five tokens", () => {
19
+ expect(buildDropdownClasses('selection', 'single', 'md', 'default')).toBe('ux4g-dropdown ux4g-dropdown-selection ux4g-dropdown-single ux4g-dropdown-md ux4g-dropdown-default');
20
+ });
21
+ it("type='button' mode='multi' size='lg' state='error' open=true → includes is-open", () => {
22
+ expect(buildDropdownClasses('button', 'multi', 'lg', 'error', true)).toBe('ux4g-dropdown ux4g-dropdown-button ux4g-dropdown-multi ux4g-dropdown-lg ux4g-dropdown-error is-open');
23
+ });
24
+ it("type='overflow' mode='single' size='sm' state='default' open=false → no is-open", () => {
25
+ const result = buildDropdownClasses('overflow', 'single', 'sm', 'default', false);
26
+ expect(result).not.toContain('is-open');
27
+ expect(result).toBe('ux4g-dropdown ux4g-dropdown-overflow ux4g-dropdown-single ux4g-dropdown-sm ux4g-dropdown-default');
28
+ });
29
+ });
30
+ // ── buildComboboxClasses ──────────────────────────────────────────────────────
31
+ // Requirements: 4.12
32
+ describe('buildComboboxClasses', () => {
33
+ it("type='single' size='md' state='default' → all four tokens", () => {
34
+ expect(buildComboboxClasses('single', 'md', 'default')).toBe('ux4g-combobox ux4g-combobox-single ux4g-combobox-md ux4g-combobox-default');
35
+ });
36
+ it("type='multi' size='lg' state='error' open=true → includes is-open", () => {
37
+ expect(buildComboboxClasses('multi', 'lg', 'error', true)).toBe('ux4g-combobox ux4g-combobox-multi ux4g-combobox-lg ux4g-combobox-error is-open');
38
+ });
39
+ });
40
+ // ── buildModalBackdropClasses ─────────────────────────────────────────────────
41
+ // Requirements: 4.15
42
+ describe('buildModalBackdropClasses', () => {
43
+ it("opacity='50' → base + opacity only", () => {
44
+ expect(buildModalBackdropClasses('50')).toBe('ux4g-modal-backdrop ux4g-modal-backdrop-50');
45
+ });
46
+ it("opacity='75' blur=true open=true → includes blur and is-open", () => {
47
+ expect(buildModalBackdropClasses('75', true, true)).toBe('ux4g-modal-backdrop ux4g-modal-backdrop-75 ux4g-modal-backdrop-blur is-open');
48
+ });
49
+ it("opacity='25' blur=false open=false → no blur, no is-open", () => {
50
+ const result = buildModalBackdropClasses('25', false, false);
51
+ expect(result).not.toContain('ux4g-modal-backdrop-blur');
52
+ expect(result).not.toContain('is-open');
53
+ expect(result).toBe('ux4g-modal-backdrop ux4g-modal-backdrop-25');
54
+ });
55
+ });
56
+ // ── buildModalBoxClasses ──────────────────────────────────────────────────────
57
+ // Requirements: 4.16
58
+ describe('buildModalBoxClasses', () => {
59
+ it("size='m' → base + size", () => {
60
+ expect(buildModalBoxClasses('m')).toBe('ux4g-modal-box ux4g-modal-m');
61
+ });
62
+ it("size='l' centerContent=true → includes center-content", () => {
63
+ expect(buildModalBoxClasses('l', true)).toBe('ux4g-modal-box ux4g-modal-l ux4g-modal-center-content');
64
+ });
65
+ it("size='s' centerContent=false → no center-content", () => {
66
+ const result = buildModalBoxClasses('s', false);
67
+ expect(result).not.toContain('ux4g-modal-center-content');
68
+ expect(result).toBe('ux4g-modal-box ux4g-modal-s');
69
+ });
70
+ });
71
+ // ── buildAlertClasses ─────────────────────────────────────────────────────────
72
+ // Requirements: 4.19
73
+ describe('buildAlertClasses', () => {
74
+ it("variant='info' → base + variant only", () => {
75
+ expect(buildAlertClasses('info')).toBe('ux4g-alert ux4g-alert-info');
76
+ });
77
+ it("variant='warning' layout='center' → includes center modifier", () => {
78
+ expect(buildAlertClasses('warning', 'center')).toBe('ux4g-alert ux4g-alert-warning ux4g-alert-center');
79
+ });
80
+ it("variant='error' layout='wide' → includes wide modifier", () => {
81
+ expect(buildAlertClasses('error', 'wide')).toBe('ux4g-alert ux4g-alert-error ux4g-alert-wide');
82
+ });
83
+ it("variant='success' layout='fluid' → no layout modifier", () => {
84
+ const result = buildAlertClasses('success', 'fluid');
85
+ expect(result).not.toContain('ux4g-alert-fluid');
86
+ expect(result).toBe('ux4g-alert ux4g-alert-success');
87
+ });
88
+ });
89
+ // ── buildContextAlertClasses ──────────────────────────────────────────────────
90
+ // Requirements: 4.20
91
+ describe('buildContextAlertClasses', () => {
92
+ it("variant='info' → ux4g-context-alert + variant modifier", () => {
93
+ expect(buildContextAlertClasses('info')).toBe('ux4g-context-alert ux4g-alert-info');
94
+ });
95
+ it("variant='error' → ux4g-context-alert + variant modifier", () => {
96
+ expect(buildContextAlertClasses('error')).toBe('ux4g-context-alert ux4g-alert-error');
97
+ });
98
+ });
99
+ // ── buildAlertContainerClasses ────────────────────────────────────────────────
100
+ // Requirements: 4.22
101
+ describe('buildAlertContainerClasses', () => {
102
+ it("position='top-right' → base + position", () => {
103
+ expect(buildAlertContainerClasses('top-right')).toBe('ux4g-alert-container ux4g-alert-top-right');
104
+ });
105
+ it("position='bottom-left' → base + position", () => {
106
+ expect(buildAlertContainerClasses('bottom-left')).toBe('ux4g-alert-container ux4g-alert-bottom-left');
107
+ });
108
+ });
109
+ // ── buildSearchContainerClasses ───────────────────────────────────────────────
110
+ // Requirements: 4.24
111
+ describe('buildSearchContainerClasses', () => {
112
+ it("size='m' → base + size", () => {
113
+ expect(buildSearchContainerClasses('m')).toBe('ux4g-search-container ux4g-search-m');
114
+ });
115
+ it("size='s' → base + size", () => {
116
+ expect(buildSearchContainerClasses('s')).toBe('ux4g-search-container ux4g-search-s');
117
+ });
118
+ it("size='lg' → base + size", () => {
119
+ expect(buildSearchContainerClasses('lg')).toBe('ux4g-search-container ux4g-search-lg');
120
+ });
121
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Property-based tests for Phase 7 build functions
3
+ *
4
+ * Property 1: Pagination class correctly toggles dotted variant and style modifiers
5
+ * Property 2: Table class contains all required tokens and correctly toggles divider, zebra, and boolean flags
6
+ * Property 3: Popover class contains required tokens and correctly toggles show
7
+ * Property 4: Tooltip class contains all required tokens for all placement and size combinations
8
+ * Property 5: Tab class contains all required tokens and correctly toggles vertical
9
+ * Property 6: Icon button class contains all required tokens and correctly toggles pill
10
+ * Property 7: Extra param is always appended and never duplicated across all build functions
11
+ */
12
+ import * as fc from 'fast-check';
13
+ import { buildPaginationClasses, buildTableClasses, buildPopoverClasses, buildTooltipClasses, buildTabClasses, buildIconButtonClasses, } from '../../src/types';
14
+ /**
15
+ * Property 1: Pagination class string contains required tokens and correctly applies dotted variant and style modifiers
16
+ * Tag: Feature: ux4g-phase7-components, Property 1
17
+ * Validates: Requirements 12.1, 12.2, 12.3, 12.4, 12.5
18
+ */
19
+ describe('Property 1: Pagination class correctly toggles dotted variant and style modifiers', () => {
20
+ it('Feature: ux4g-phase7-components, Property 1', () => {
21
+ fc.assert(fc.property(fc.constantFrom('default', 'dotted'), fc.constantFrom('default', 'solid', 'translucent'), (variant, paginationStyle) => {
22
+ const result = buildPaginationClasses(variant, paginationStyle);
23
+ const tokens = result.split(' ');
24
+ // Always contains base class
25
+ const hasBase = tokens.includes('ux4g-pagination');
26
+ // Dotted variant toggles correctly
27
+ const dottedCorrect = variant === 'dotted'
28
+ ? tokens.includes('ux4g-pagination-dotted')
29
+ : !tokens.includes('ux4g-pagination-dotted');
30
+ // Style modifiers only apply when dotted; mutually exclusive
31
+ let styleCorrect;
32
+ if (variant === 'dotted' && paginationStyle === 'solid') {
33
+ styleCorrect = tokens.includes('ux4g-pagination-solid') && !tokens.includes('ux4g-pagination-translucent');
34
+ }
35
+ else if (variant === 'dotted' && paginationStyle === 'translucent') {
36
+ styleCorrect = tokens.includes('ux4g-pagination-translucent') && !tokens.includes('ux4g-pagination-solid');
37
+ }
38
+ else {
39
+ // variant='default' (any style) or variant='dotted' paginationStyle='default' — no style modifier
40
+ styleCorrect = !tokens.includes('ux4g-pagination-solid') && !tokens.includes('ux4g-pagination-translucent');
41
+ }
42
+ // No duplicates
43
+ const noDuplicates = tokens.length === new Set(tokens).size;
44
+ return hasBase && dottedCorrect && styleCorrect && noDuplicates;
45
+ }), { numRuns: 25 });
46
+ });
47
+ });
48
+ /**
49
+ * Property 2: Table class string contains all required tokens and correctly toggles divider, zebra, and boolean modifier flags
50
+ * Tag: Feature: ux4g-phase7-components, Property 2
51
+ * Validates: Requirements 12.6, 12.7, 12.8, 12.9, 12.10, 12.11, 12.12, 12.13
52
+ */
53
+ describe('Property 2: Table class contains all required tokens and correctly toggles divider, zebra, and boolean flags', () => {
54
+ it('Feature: ux4g-phase7-components, Property 2', () => {
55
+ fc.assert(fc.property(fc.constantFrom('s', 'm', 'lg'), fc.constantFrom('row', 'column', 'none'), fc.constantFrom('none', 'rows', 'cols'), fc.boolean(), fc.boolean(), fc.boolean(), fc.boolean(), (size, divider, zebra, interactive, sortable, resizable, headerBrand) => {
56
+ const result = buildTableClasses(size, divider, zebra, interactive, sortable, resizable, headerBrand);
57
+ const tokens = result.split(' ');
58
+ // Always contains base and size
59
+ const hasBase = tokens.includes('ux4g-table');
60
+ const hasSize = tokens.includes(`ux4g-table-${size}`);
61
+ // Divider modifiers are mutually exclusive
62
+ let dividerCorrect;
63
+ if (divider === 'column') {
64
+ dividerCorrect = tokens.includes('ux4g-table-column-dividers') && !tokens.includes('ux4g-table-no-row-dividers');
65
+ }
66
+ else if (divider === 'none') {
67
+ dividerCorrect = tokens.includes('ux4g-table-no-row-dividers') && !tokens.includes('ux4g-table-column-dividers');
68
+ }
69
+ else {
70
+ // divider === 'row' — no modifier
71
+ dividerCorrect = !tokens.includes('ux4g-table-column-dividers') && !tokens.includes('ux4g-table-no-row-dividers');
72
+ }
73
+ // Zebra modifiers are mutually exclusive
74
+ let zebraCorrect;
75
+ if (zebra === 'rows') {
76
+ zebraCorrect = tokens.includes('ux4g-table-zebra-rows') && !tokens.includes('ux4g-table-zebra-cols');
77
+ }
78
+ else if (zebra === 'cols') {
79
+ zebraCorrect = tokens.includes('ux4g-table-zebra-cols') && !tokens.includes('ux4g-table-zebra-rows');
80
+ }
81
+ else {
82
+ // zebra === 'none' — no modifier
83
+ zebraCorrect = !tokens.includes('ux4g-table-zebra-rows') && !tokens.includes('ux4g-table-zebra-cols');
84
+ }
85
+ // Boolean flags toggle independently
86
+ const interactiveCorrect = interactive ? tokens.includes('ux4g-table-interactive') : !tokens.includes('ux4g-table-interactive');
87
+ const sortableCorrect = sortable ? tokens.includes('ux4g-table-sortable') : !tokens.includes('ux4g-table-sortable');
88
+ const resizableCorrect = resizable ? tokens.includes('ux4g-table-resizable') : !tokens.includes('ux4g-table-resizable');
89
+ const headerBrandCorrect = headerBrand ? tokens.includes('ux4g-table-header-brand') : !tokens.includes('ux4g-table-header-brand');
90
+ // No duplicates
91
+ const noDuplicates = tokens.length === new Set(tokens).size;
92
+ return hasBase && hasSize && dividerCorrect && zebraCorrect
93
+ && interactiveCorrect && sortableCorrect && resizableCorrect && headerBrandCorrect
94
+ && noDuplicates;
95
+ }), { numRuns: 25 });
96
+ });
97
+ });
98
+ /**
99
+ * Property 3: Popover class string contains required tokens and correctly toggles show
100
+ * Tag: Feature: ux4g-phase7-components, Property 3
101
+ * Validates: Requirements 12.14, 12.15, 12.16
102
+ */
103
+ describe('Property 3: Popover class contains required tokens and correctly toggles show', () => {
104
+ it('Feature: ux4g-phase7-components, Property 3', () => {
105
+ fc.assert(fc.property(fc.constantFrom('top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end'), fc.boolean(), (placement, show) => {
106
+ const result = buildPopoverClasses(placement, show);
107
+ const tokens = result.split(' ');
108
+ // Always contains base and placement
109
+ const hasBase = tokens.includes('ux4g-popover');
110
+ const hasPlacement = tokens.includes(`ux4g-popover-${placement}`);
111
+ // show toggles correctly
112
+ const showCorrect = show ? tokens.includes('show') : !tokens.includes('show');
113
+ // No duplicates
114
+ const noDuplicates = tokens.length === new Set(tokens).size;
115
+ return hasBase && hasPlacement && showCorrect && noDuplicates;
116
+ }), { numRuns: 25 });
117
+ });
118
+ });
119
+ /**
120
+ * Property 4: Tooltip class string contains all required tokens for all valid placement and size combinations
121
+ * Tag: Feature: ux4g-phase7-components, Property 4
122
+ * Validates: Requirements 12.17, 12.18
123
+ */
124
+ describe('Property 4: Tooltip class contains all required tokens for all placement and size combinations', () => {
125
+ it('Feature: ux4g-phase7-components, Property 4', () => {
126
+ fc.assert(fc.property(fc.constantFrom('top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right', 'left-center', 'right-center'), fc.constantFrom('s', 'xs'), (placement, size) => {
127
+ const result = buildTooltipClasses(placement, size);
128
+ const tokens = result.split(' ');
129
+ // Always contains base, placement, and size
130
+ const hasBase = tokens.includes('ux4g-tooltip');
131
+ const hasPlacement = tokens.includes(`ux4g-tooltip-${placement}`);
132
+ const hasSize = tokens.includes(`ux4g-tooltip-${size}`);
133
+ // No duplicates
134
+ const noDuplicates = tokens.length === new Set(tokens).size;
135
+ return hasBase && hasPlacement && hasSize && noDuplicates;
136
+ }), { numRuns: 25 });
137
+ });
138
+ });
139
+ /**
140
+ * Property 5: Tab class string contains all required tokens and correctly toggles vertical modifier
141
+ * Tag: Feature: ux4g-phase7-components, Property 5
142
+ * Validates: Requirements 12.19, 12.20, 12.21
143
+ */
144
+ describe('Property 5: Tab class contains all required tokens and correctly toggles vertical', () => {
145
+ it('Feature: ux4g-phase7-components, Property 5', () => {
146
+ fc.assert(fc.property(fc.constantFrom('underline', 'pill'), fc.constantFrom('sm', 'md', 'lg'), fc.boolean(), (variant, size, vertical) => {
147
+ const result = buildTabClasses(variant, size, vertical);
148
+ const tokens = result.split(' ');
149
+ // Always contains base, variant, and size
150
+ const hasBase = tokens.includes('ux4g-tab');
151
+ const hasVariant = tokens.includes(`ux4g-tab-${variant}`);
152
+ const hasSize = tokens.includes(`ux4g-tab-${size}`);
153
+ // vertical toggles correctly
154
+ const verticalCorrect = vertical
155
+ ? tokens.includes('ux4g-tab-vertical')
156
+ : !tokens.includes('ux4g-tab-vertical');
157
+ // No duplicates
158
+ const noDuplicates = tokens.length === new Set(tokens).size;
159
+ return hasBase && hasVariant && hasSize && verticalCorrect && noDuplicates;
160
+ }), { numRuns: 25 });
161
+ });
162
+ });
163
+ /**
164
+ * Property 6: Icon button class string contains all required tokens and correctly toggles pill modifier
165
+ * Tag: Feature: ux4g-phase7-components, Property 6
166
+ * Validates: Requirements 12.22, 12.23, 12.24
167
+ */
168
+ describe('Property 6: Icon button class contains all required tokens and correctly toggles pill', () => {
169
+ it('Feature: ux4g-phase7-components, Property 6', () => {
170
+ fc.assert(fc.property(fc.constantFrom('primary', 'outline-primary', 'tonal-primary', 'text-primary'), fc.constantFrom('xl', 'lg', 'md', 'sm', 'xs'), fc.boolean(), (variant, size, pill) => {
171
+ const result = buildIconButtonClasses(variant, size, pill);
172
+ const tokens = result.split(' ');
173
+ // Always contains base, variant, and size
174
+ const hasBase = tokens.includes('ux4g-icon-btn');
175
+ const hasVariant = tokens.includes(`ux4g-icon-btn-${variant}`);
176
+ const hasSize = tokens.includes(`ux4g-icon-btn-${size}`);
177
+ // pill toggles correctly
178
+ const pillCorrect = pill
179
+ ? tokens.includes('ux4g-icon-btn-pill')
180
+ : !tokens.includes('ux4g-icon-btn-pill');
181
+ // No duplicates
182
+ const noDuplicates = tokens.length === new Set(tokens).size;
183
+ return hasBase && hasVariant && hasSize && pillCorrect && noDuplicates;
184
+ }), { numRuns: 25 });
185
+ });
186
+ });
187
+ /**
188
+ * Property 7: Extra param is always appended as a space-separated token and never duplicates existing tokens
189
+ * Tag: Feature: ux4g-phase7-components, Property 7
190
+ * Validates: Requirements 12.25
191
+ */
192
+ describe('Property 7: Extra param is always appended and never duplicated across all build functions', () => {
193
+ it('Feature: ux4g-phase7-components, Property 7', () => {
194
+ // Generator for a non-empty extra token with no spaces (valid CSS class name)
195
+ const extraArb = fc.stringMatching(/^[a-z][a-z0-9-]*$/);
196
+ fc.assert(fc.property(extraArb, (extra) => {
197
+ const results = [
198
+ buildPaginationClasses('dotted', 'solid', extra),
199
+ buildTableClasses('m', 'column', 'cols', true, true, true, true, extra),
200
+ buildPopoverClasses('bottom', true, extra),
201
+ buildTooltipClasses('top-center', 's', extra),
202
+ buildTabClasses('underline', 'md', true, extra),
203
+ buildIconButtonClasses('primary', 'md', true, extra),
204
+ ];
205
+ return results.every((result) => {
206
+ const tokens = result.split(' ');
207
+ // Extra token appears in result
208
+ const hasExtra = tokens.includes(extra);
209
+ // No duplicates
210
+ const noDuplicates = tokens.length === new Set(tokens).size;
211
+ // Extra token appears exactly once
212
+ const exactlyOnce = tokens.filter((t) => t === extra).length === 1;
213
+ return hasExtra && noDuplicates && exactlyOnce;
214
+ });
215
+ }), { numRuns: 25 });
216
+ });
217
+ });
@@ -0,0 +1 @@
1
+ export {};