css_modules 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 431374aa2a26649b2dac684cf81efe66e419c84c
4
- data.tar.gz: 2dffe66a072a52b0c60074940be0774a6513e7a1
3
+ metadata.gz: dce9ca6ecb86907f4b2b6dd0b19eed2769d56f8a
4
+ data.tar.gz: ef5476565fb76bb21618521dbe9e7e57c0adbef0
5
5
  SHA512:
6
- metadata.gz: b89042953316ab3a5b1b17c7c46eb5d2882e529415f5fb7a1c5247d3628ca1cd11aa796b09c9d0318c89578fe384a896f014d124f3f5616d07047b073fcc4c5f
7
- data.tar.gz: 9c6387bfb0e5b68e7f5879c2999e4cd994c1b3ddfa03449ac18b5213f276ca7bff7f6c4abe9227732f8430134f68a59d2db39673594b9128fc2f992d3656dc5e
6
+ metadata.gz: 386082a080e70bef2535c1bb7730f6203969f8d7655563572b427ffffbbcb96d197ac638e2a4abf8db14bbaaf50529ac414073e7703e8fa0f1ad10d397e79b38
7
+ data.tar.gz: fee03dea66978d5af49efb5a68b0702e0fc85ccfb8d1cca2ad683358dec4c325f6acfc13276bea7981c2f8b7503888a5a3f6111724e57254f280837f483587d6
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # CSSModules
2
2
 
3
+ [![Build Status](https://travis-ci.org/rmosolgo/css_modules.svg?branch=master)](https://travis-ci.org/rmosolgo/css_modules)
4
+ [![Gem Version](https://badge.fury.io/rb/css_modules.svg)](https://badge.fury.io/rb/css_modules)
5
+
3
6
  An alternative to "magic string" classnames in Sass or SCSS. Currently supports Sprockets 2 only 😖.
4
7
 
5
8
  Thanks to [Fatih Kadir Akın](https://twitter.com/fkadev) for his post, ["How I Implemented CSS Modules in Ruby on Rails, Easily"](https://medium.com/@fkadev/how-i-implemented-css-modules-to-ruby-on-rails-easily-abb324ce22d), which led the way on this idea!
@@ -118,6 +121,8 @@ $ gem install css_modules
118
121
  - Support plain `.css`
119
122
  - Use Sass's built-in parser?
120
123
  - Support Sprockets 3+
124
+ - Check for hash collisions in development
125
+ - Fix bundle cache
121
126
 
122
127
  ## License
123
128
 
@@ -0,0 +1,59 @@
1
+ // Usage:
2
+ //
3
+ // - Call with a module name + selector name to get a transformed (opaque) selector
4
+ //
5
+ // ```js
6
+ // CSSModule("events_index", "header")
7
+ // // => "..." (some opaque string that matches the stylesheet)
8
+ // ```
9
+ //
10
+ // - Call with a module name to get a function for modulizing selectors
11
+ //
12
+ // ```js
13
+ // var eventsModule = CSSModule("events_index")
14
+ // var headerSelector = eventsModule("header")
15
+ // var footerSelector = eventsModule("footer")
16
+ // ```
17
+ //
18
+ // This behavior has to match `CSSModules::Rewrite` in Ruby
19
+ // so that generated selectors match.
20
+ var CSSModule = (function() {
21
+ // This matches Transform.compute_hash in Ruby
22
+ var HASH_LIMIT = 10009;
23
+ var SUM_SIZE = 4;
24
+ function computeHash(inputString) {
25
+ var bytesCount = 0;
26
+ var stringSum = 0;
27
+ var byte;
28
+ for(var i = 0; i < inputString.length; i++) {
29
+ byte = inputString.charCodeAt(i);
30
+ stringSum += (byte * Math.pow(256, bytesCount))
31
+ bytesCount += 1;
32
+ bytesCount %= SUM_SIZE;
33
+ }
34
+
35
+ return stringSum % HASH_LIMIT;
36
+ };
37
+
38
+ function modulizeSelector(moduleName, selectorName, environment) {
39
+ if (environment === "production") {
40
+ return moduleName.substr(0, 1) + computeHash(moduleName + selectorName) + selectorName.substr(0, 1);
41
+ } else {
42
+ return moduleName + "_" + computeHash(moduleName + selectorName) + "_" + selectorName;
43
+ }
44
+ }
45
+
46
+ function _CSSModule(moduleName, selectorName, environment) {
47
+ environment || (environment = "<% Rails.env %>")
48
+
49
+ if (selectorName) {
50
+ return modulizeSelector(moduleName, selectorName, environment);
51
+ } else {
52
+ return function(selectorName) {
53
+ return modulizeSelector(moduleName, selectorName, environment);
54
+ };
55
+ }
56
+ };
57
+
58
+ return _CSSModule;
59
+ })();
@@ -1,5 +1,5 @@
1
1
  require "css_parser"
2
- require "base64"
2
+ require "css_modules/transform"
3
3
 
4
4
  module CSSModules
5
5
  module Rewrite
@@ -30,9 +30,12 @@ module CSSModules
30
30
 
31
31
  # Combine `module_name` and `selector`, but don't prepend a `.` or `#`
32
32
  # because this value will be inserted into the HTML page as `class=` or `id=`
33
+ # @param module_name [String] A CSS module name
34
+ # @param selector [String] A would-be DOM selector (without the leading `.` or `#`)
35
+ # @return [String] An opaque selector for this module-selector pair
33
36
  def modulize_selector(module_name, selector)
34
- transformed_name = transform_name(module_name)
35
- "#{transformed_name}_#{selector}"
37
+ tran = Rails.env.production? ? Transform::ProductionTransform : Transform::DevelopmentTransform
38
+ tran.transform(module_name, selector)
36
39
  end
37
40
 
38
41
  private
@@ -44,7 +47,7 @@ module CSSModules
44
47
  if matches.nil?
45
48
  selector
46
49
  else
47
- module_name = transform_name(matches[:module_name])
50
+ module_name = matches[:module_name]
48
51
  declaration_parts = matches[:declarations].split(" ")
49
52
  declaration_parts
50
53
  .map { |declaration_or_operator| rebuild_selector(module_name, declaration_or_operator) }
@@ -57,19 +60,12 @@ module CSSModules
57
60
  def rebuild_selector(module_ident, selector)
58
61
  case selector[0]
59
62
  when "#"
60
- "##{module_ident}_#{selector[1..-1]}"
63
+ "##{modulize_selector(module_ident, selector[1..-1])}"
61
64
  when "."
62
- ".#{module_ident}_#{selector[1..-1]}"
65
+ ".#{modulize_selector(module_ident, selector[1..-1])}"
63
66
  else
64
67
  selector
65
68
  end
66
69
  end
67
-
68
- def transform_name(css_module_name)
69
- # Some base64 characters aren't valid for CSS (eg, `=`)
70
- opaque_string = Base64.encode64(css_module_name).gsub(/[^a-zA-Z0-9]/, "")
71
- # p [css_module_name, opaque_string]
72
- "#{opaque_string}_#{css_module_name}"
73
- end
74
70
  end
75
71
  end
@@ -0,0 +1,38 @@
1
+ module CSSModules
2
+ module Transform
3
+ # Hash outputs will be within the range `0..HASH_LIMIT-1`
4
+ HASH_LIMIT = 10009
5
+ # How big of a chunk should we use for folding over the string?
6
+ SUM_SIZE = 4
7
+
8
+ # Generate a short, random-ish token for `input_string`.
9
+ # This has to be replicable in JS.
10
+ # Ruby's `#hash` is randomly seeded, so we can't reuse that!
11
+ # @param input_string [String] A string to hash
12
+ # @return [String] a deterministic output for `input_string`
13
+ def self.compute_hash(input_string)
14
+ bytes_count = 0
15
+ string_sum = 0
16
+
17
+ input_string.each_byte do |byte|
18
+ string_sum += byte * (256 ** bytes_count)
19
+ bytes_count += 1
20
+ bytes_count %= SUM_SIZE
21
+ end
22
+
23
+ string_sum % HASH_LIMIT
24
+ end
25
+
26
+ module DevelopmentTransform
27
+ def self.transform(module_name, selector_name)
28
+ "#{module_name}_#{Transform.compute_hash(module_name + selector_name)}_#{selector_name}"
29
+ end
30
+ end
31
+
32
+ module ProductionTransform
33
+ def self.transform(module_name, selector_name)
34
+ "#{module_name[0]}#{Transform.compute_hash(module_name + selector_name)}#{selector_name[0]}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module CSSModules
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: css_modules
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
@@ -78,9 +78,10 @@ files:
78
78
  - Rakefile
79
79
  - lib/css_modules.rb
80
80
  - lib/css_modules/assets/base64.js
81
- - lib/css_modules/assets/css_module.js
81
+ - lib/css_modules/assets/css_module.js.erb
82
82
  - lib/css_modules/engine.rb
83
83
  - lib/css_modules/rewrite.rb
84
+ - lib/css_modules/transform.rb
84
85
  - lib/css_modules/version.rb
85
86
  - lib/css_modules/view_helper.rb
86
87
  homepage: https://github.com/rmosolgo/css_modules
@@ -1,31 +0,0 @@
1
- // Usage:
2
- //
3
- // - Call with a module name + selector name to get a transformed (opaque) selector
4
- //
5
- // ```js
6
- // CSSModule("events_index", "header")
7
- // // => "..." (some opaque string that matches the stylesheet)
8
- // ```
9
- //
10
- // - Call with a module name to get a function for modulizing selectors
11
- //
12
- // ```js
13
- // var eventsModule = CSSModule("events_index")
14
- // var headerSelector = eventsModule("header")
15
- // var footerSelector = eventsModule("footer")
16
- // ```
17
- //
18
- // This behavior has to match `CSSModules::Rewrite` in Ruby
19
- // so that generated selectors match.
20
- function CSSModule(moduleName, selectorName) {
21
- // This matches `Rewrite`:
22
- var opaqueString = btoa(moduleName).replace(/[^a-zA-Z0-9]/g, "")
23
- var transformedModuleName = opaqueString + "_" + moduleName;
24
- if (selectorName) {
25
- return transformedModuleName + "_" + selectorName;
26
- } else {
27
- return function(selectorName) {
28
- return transformedModuleName + "_" + selectorName;
29
- };
30
- }
31
- };