ripple 0.2.169 → 0.2.170

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.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Ripple is an elegant TypeScript UI framework",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.2.169",
6
+ "version": "0.2.170",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -81,6 +81,6 @@
81
81
  "typescript": "^5.9.2"
82
82
  },
83
83
  "peerDependencies": {
84
- "ripple": "0.2.169"
84
+ "ripple": "0.2.170"
85
85
  }
86
86
  }
@@ -845,6 +845,26 @@ function get_parent_rules(rule) {
845
845
  return rules;
846
846
  }
847
847
 
848
+ /**
849
+ * Check if a CSS rule contains animation or animation-name properties
850
+ * @param {Compiler.AST.CSS.Rule} rule
851
+ * @returns {boolean}
852
+ */
853
+ function rule_has_animation(rule) {
854
+ if (!rule.block) return false;
855
+
856
+ for (const child of rule.block.children) {
857
+ if (child.type === 'Declaration') {
858
+ const prop = child.property?.toLowerCase();
859
+ if (prop === 'animation' || prop === 'animation-name') {
860
+ return true;
861
+ }
862
+ }
863
+ }
864
+
865
+ return false;
866
+ }
867
+
848
868
  export function prune_css(css, element) {
849
869
  walk(css, null, {
850
870
  Rule(node, context) {
@@ -859,14 +879,9 @@ export function prune_css(css, element) {
859
879
 
860
880
  seen.clear();
861
881
 
862
- if (
863
- apply_selector(
864
- selectors,
865
- /** @type {Compiler.AST.CSS.Rule} */ (node.metadata.rule),
866
- element,
867
- BACKWARD,
868
- )
869
- ) {
882
+ const rule = /** @type {Compiler.AST.CSS.Rule} */ (node.metadata.rule);
883
+
884
+ if (apply_selector(selectors, rule, element, BACKWARD) || rule_has_animation(rule)) {
870
885
  node.metadata.used = true;
871
886
  }
872
887
 
@@ -195,7 +195,7 @@ const visitors = {
195
195
  const character = state.code.original[index];
196
196
 
197
197
  if (regex_css_name_boundary.test(character)) {
198
- if (character !== ' ') {
198
+ if (name) {
199
199
  const append_index = index - name.length;
200
200
  state.keyframes[name] ??= { indexes: [], local: undefined };
201
201
  if (state.keyframes[name].local) {
@@ -98,4 +98,61 @@ export component Test() {
98
98
  expect(css).toContain('@keyframes foo');
99
99
  expect(css).toContain('@keyframes bar');
100
100
  });
101
+
102
+ it('handles animation property referencing keyframes (not marking as unused)', () => {
103
+ const source = `
104
+ export component Parent() {
105
+ <div class="parent">
106
+ <Child />
107
+ </div>
108
+
109
+ <style>
110
+ /* Scoped keyframe - only usable within Parent */
111
+ @keyframes slideIn {
112
+ from { transform: translateX(-100%); }
113
+ to { transform: translateX(0); }
114
+ }
115
+
116
+ /* Global keyframe - usable in any component */
117
+ @keyframes -global-fadeIn {
118
+ 0% { opacity: 0; }
119
+ 100% { opacity: 1; }
120
+ }
121
+
122
+ .parent {
123
+ animation: slideIn 1s;
124
+ }
125
+ </style>
126
+ }
127
+
128
+ component Child() {
129
+ <div class="child">{'Child content'}</div>
130
+
131
+ <style>
132
+ .child {
133
+ animation: fadeIn 3s; /* Uses global fadeIn from Parent */
134
+ }
135
+ </style>
136
+ }`;
137
+ const { css } = compile(source, 'test.ripple');
138
+
139
+ // Parent should have scoped slideIn and global fadeIn
140
+ expect(css).toMatch(/@keyframes ripple-[a-z0-9]+-slideIn/);
141
+ expect(css).toContain('@keyframes fadeIn');
142
+ expect(css).not.toContain('-global-fadeIn');
143
+
144
+ // Parent .parent should reference scoped slideIn
145
+ expect(css).toMatch(
146
+ /\.parent\.ripple-[a-z0-9]+\s*{[\s\S]*?animation:\s*ripple-[a-z0-9]+-slideIn 1s/,
147
+ );
148
+
149
+ // .parent should NOT be marked as unused
150
+ expect(css).not.toContain('(unused) .parent');
151
+
152
+ // Child .child should reference global fadeIn
153
+ expect(css).toMatch(/\.child\.ripple-[a-z0-9]+\s*{[\s\S]*?animation:\s*fadeIn 3s/);
154
+
155
+ // .child should NOT be marked as unused
156
+ expect(css).not.toContain('(unused) .child');
157
+ });
101
158
  });