shimmer 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/lib/shimmer/utils/remote_navigation.rb +26 -7
- data/lib/shimmer/version.rb +1 -1
- data/package.json +3 -1
- data/rollup.config.js +1 -1
- data/src/controllers/remote-navigation.ts +9 -0
- data/src/index.ts +27 -12
- data/src/modal.ts +1 -28
- data/src/popover.ts +89 -0
- data/src/util.ts +31 -0
- data/yarn.lock +10 -0
- metadata +9 -7
- data/shimmer.gemspec +0 -35
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 419d4bba740070b286202f099a64f31929b029505bc3411a9db8b922d51e0eec
|
|
4
|
+
data.tar.gz: 5f75ac2e0c8ac3fc82335efe2dd8bd98270f9506433bfa0e894369e952fb6aef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec203c95a4fc2088731aa269c0c27577fbd59fa4070d972d6ad066d469b6203b54fb8ffafedb4295d7387e981d6a50a87ca981f8c92c9f5c624d45aed851b906
|
|
7
|
+
data.tar.gz: cdae8b03095d4f3c7f38f5ccbe47864ab41ade50bf1e2d45fe3da2e112e2a11e3d733ed73d2b581a833be9d6f5f263795aff008ccfcd5da51d45c52227a560c9
|
|
@@ -6,7 +6,7 @@ module Shimmer
|
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
8
|
def ui
|
|
9
|
-
@ui ||= RemoteNavigator.new
|
|
9
|
+
@ui ||= RemoteNavigator.new(self)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def default_render
|
|
@@ -17,7 +17,7 @@ module Shimmer
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
helper_method :modal_path
|
|
20
|
-
def modal_path(url, id: nil, size: nil, close:
|
|
20
|
+
def modal_path(url, id: nil, size: nil, close: true)
|
|
21
21
|
"javascript:ui.modal.open(#{{url: url, id: id, size: size, close: close}.to_json})"
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -26,6 +26,11 @@ module Shimmer
|
|
|
26
26
|
"javascript:ui.modal.close(#{{id: id}.to_json})"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
helper_method :popover_path
|
|
30
|
+
def popover_path(url, id: nil, selector: nil, placement: nil)
|
|
31
|
+
"javascript:ui.popover.open(#{{url: url, id: id, selector: selector, placement: placement}.compact.to_json})"
|
|
32
|
+
end
|
|
33
|
+
|
|
29
34
|
def shimmer_request?
|
|
30
35
|
request.headers["X-Shimmer"].present?
|
|
31
36
|
end
|
|
@@ -42,10 +47,10 @@ module Shimmer
|
|
|
42
47
|
end
|
|
43
48
|
|
|
44
49
|
class RemoteNavigator
|
|
45
|
-
|
|
50
|
+
delegate :polymorphic_path, to: :@controller
|
|
46
51
|
|
|
47
|
-
def initialize(
|
|
48
|
-
@
|
|
52
|
+
def initialize(controller)
|
|
53
|
+
@controller = controller
|
|
49
54
|
end
|
|
50
55
|
|
|
51
56
|
def queued_updates
|
|
@@ -76,18 +81,32 @@ module Shimmer
|
|
|
76
81
|
queued_updates.push turbo_stream.remove(id)
|
|
77
82
|
end
|
|
78
83
|
|
|
79
|
-
def open_modal(path)
|
|
80
|
-
run_javascript "ui.modal.open(
|
|
84
|
+
def open_modal(path, id: nil, size: nil, close: true)
|
|
85
|
+
run_javascript "ui.modal.open(#{{url: url, id: id, size: size, close: close}.to_json})"
|
|
81
86
|
end
|
|
82
87
|
|
|
83
88
|
def close_modal
|
|
84
89
|
run_javascript "ui.modal.close()"
|
|
85
90
|
end
|
|
86
91
|
|
|
92
|
+
def open_popover(path, selector:, placement: nil)
|
|
93
|
+
run_javascript "ui.popover.open(#{{url: url, selector: selector, placement: placement}.to_json})"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def close_popover
|
|
97
|
+
run_javascript "ui.popover.close()"
|
|
98
|
+
end
|
|
99
|
+
|
|
87
100
|
def navigate_to(path)
|
|
88
101
|
close_modal
|
|
89
102
|
path = polymorphic_path(path) unless path.is_a?(String)
|
|
90
103
|
run_javascript "Turbo.visit('#{path}')"
|
|
91
104
|
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def turbo_stream
|
|
109
|
+
@controller.send(:turbo_stream)
|
|
110
|
+
end
|
|
92
111
|
end
|
|
93
112
|
end
|
data/lib/shimmer/version.rb
CHANGED
data/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nerdgeschoss/shimmer",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Simple application development in Rails",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
],
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"@hotwired/stimulus": "^3.0.1",
|
|
26
|
+
"@popperjs/core": "^2.11.0",
|
|
25
27
|
"@rails/request.js": "^0.0.6"
|
|
26
28
|
},
|
|
27
29
|
"devDependencies": {
|
data/rollup.config.js
CHANGED
data/src/index.ts
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
interface Window {
|
|
3
|
-
ui: typeof ui;
|
|
4
|
-
}
|
|
5
|
-
}
|
|
6
|
-
|
|
1
|
+
import type { Application } from "@hotwired/stimulus";
|
|
7
2
|
import { ModalPresenter } from "./modal";
|
|
3
|
+
import { PopoverPresenter } from "./popover";
|
|
4
|
+
import RemoteNavigationController from "./controllers/remote-navigation";
|
|
8
5
|
import "./touch";
|
|
9
6
|
|
|
10
|
-
export const ui = {
|
|
11
|
-
modal: new ModalPresenter(),
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
window.ui = ui;
|
|
15
|
-
|
|
16
7
|
export { registerServiceWorker } from "./serviceworker";
|
|
17
8
|
export { currentLocale } from "./locale";
|
|
9
|
+
|
|
10
|
+
declare global {
|
|
11
|
+
interface Window {
|
|
12
|
+
ui?: {
|
|
13
|
+
modal: ModalPresenter;
|
|
14
|
+
popover: PopoverPresenter;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function start({
|
|
20
|
+
application,
|
|
21
|
+
}: {
|
|
22
|
+
application: Application;
|
|
23
|
+
}): Promise<void> {
|
|
24
|
+
const root = document.createElement("div");
|
|
25
|
+
root.id = "shimmer";
|
|
26
|
+
document.body.append(root);
|
|
27
|
+
application.register("remote-navigation", RemoteNavigationController);
|
|
28
|
+
window.ui = {
|
|
29
|
+
modal: new ModalPresenter(),
|
|
30
|
+
popover: new PopoverPresenter(),
|
|
31
|
+
};
|
|
32
|
+
}
|
data/src/modal.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loaded, createElement, nextFrame, getHTML } from "./util";
|
|
2
2
|
|
|
3
3
|
export interface ModalOptions {
|
|
4
4
|
id?: string;
|
|
@@ -7,33 +7,6 @@ export interface ModalOptions {
|
|
|
7
7
|
close?: boolean;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const loaded: Promise<void> = new Promise((res) => {
|
|
11
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
12
|
-
res();
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
async function nextFrame(): Promise<void> {
|
|
17
|
-
return new Promise((res) => {
|
|
18
|
-
setTimeout(res, 10);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function getHTML(url: string): Promise<string> {
|
|
23
|
-
const response = await get(url, { headers: { "X-Shimmer": "true" } });
|
|
24
|
-
if (response.ok) {
|
|
25
|
-
return await response.response.text();
|
|
26
|
-
}
|
|
27
|
-
return "";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function createElement(parent: HTMLElement, className: string): HTMLDivElement {
|
|
31
|
-
const element = document.createElement("div");
|
|
32
|
-
element.className = className;
|
|
33
|
-
parent.append(element);
|
|
34
|
-
return element;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
10
|
export class ModalPresenter {
|
|
38
11
|
private modals: Record<string, Modal> = {};
|
|
39
12
|
|
data/src/popover.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Instance as Popper, createPopper, Placement } from "@popperjs/core";
|
|
2
|
+
import { createElement, getHTML } from "./util";
|
|
3
|
+
|
|
4
|
+
export interface PopoverOptions {
|
|
5
|
+
id?: string;
|
|
6
|
+
url: string;
|
|
7
|
+
selector?: HTMLElement | string;
|
|
8
|
+
placement?: Placement;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class PopoverPresenter {
|
|
12
|
+
private popovers: Record<string, Popover> = {};
|
|
13
|
+
private lastClickedElement?: HTMLElement;
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
document.addEventListener("click", this.trackElement);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async open(options: PopoverOptions): Promise<void> {
|
|
20
|
+
const id = (options.id = options.id ?? "default-popover");
|
|
21
|
+
options.selector = options.selector ?? this.lastClickedElement;
|
|
22
|
+
(this.popovers[id] = new Popover()).open(options);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async close({ id }: { id?: string } = {}): Promise<void> {
|
|
26
|
+
let promise: Promise<unknown> | null = null;
|
|
27
|
+
if (id) {
|
|
28
|
+
promise = this.popovers[id]?.close();
|
|
29
|
+
delete this.popovers[id];
|
|
30
|
+
} else {
|
|
31
|
+
promise = Promise.all(Object.values(this.popovers).map((e) => e.close()));
|
|
32
|
+
this.popovers = {};
|
|
33
|
+
}
|
|
34
|
+
await promise;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private trackElement = (event: MouseEvent): void => {
|
|
38
|
+
this.lastClickedElement = event.target as HTMLElement;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class Popover {
|
|
43
|
+
private popper?: Popper;
|
|
44
|
+
private popoverDiv?: HTMLDivElement;
|
|
45
|
+
|
|
46
|
+
async open({ url, selector, placement }: PopoverOptions): Promise<void> {
|
|
47
|
+
const root =
|
|
48
|
+
typeof selector === "string"
|
|
49
|
+
? document.querySelector(selector)
|
|
50
|
+
: selector;
|
|
51
|
+
if (!root) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const popoverDiv = createElement(document.body, "popover");
|
|
55
|
+
const arrow = createElement(popoverDiv, "popover__arrow");
|
|
56
|
+
arrow.setAttribute("data-popper-arrow", "true");
|
|
57
|
+
const content = createElement(popoverDiv, "popover__content");
|
|
58
|
+
content.innerHTML = await getHTML(url);
|
|
59
|
+
this.popper = createPopper(root, popoverDiv, {
|
|
60
|
+
placement: placement ?? "auto",
|
|
61
|
+
modifiers: [
|
|
62
|
+
{
|
|
63
|
+
name: "offset",
|
|
64
|
+
options: {
|
|
65
|
+
offset: [0, 8],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
this.popoverDiv = popoverDiv;
|
|
71
|
+
document.addEventListener("click", this.clickOutside);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async close(): Promise<void> {
|
|
75
|
+
this.popper?.destroy();
|
|
76
|
+
this.popper = undefined;
|
|
77
|
+
document.removeEventListener("click", this.clickOutside);
|
|
78
|
+
this.popoverDiv?.remove();
|
|
79
|
+
this.popoverDiv = undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private clickOutside = (event: MouseEvent): void => {
|
|
83
|
+
if (this.popoverDiv?.contains(event.target as HTMLElement)) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
this.close();
|
|
88
|
+
};
|
|
89
|
+
}
|
data/src/util.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { get } from "@rails/request.js";
|
|
2
|
+
|
|
3
|
+
export async function getHTML(url: string): Promise<string> {
|
|
4
|
+
const response = await get(url, { headers: { "X-Shimmer": "true" } });
|
|
5
|
+
if (response.ok) {
|
|
6
|
+
return await response.response.text();
|
|
7
|
+
}
|
|
8
|
+
return "";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const loaded: Promise<void> = new Promise((res) => {
|
|
12
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
13
|
+
res();
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export async function nextFrame(): Promise<void> {
|
|
18
|
+
return new Promise((res) => {
|
|
19
|
+
setTimeout(res, 10);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function createElement(
|
|
24
|
+
parent: HTMLElement,
|
|
25
|
+
className: string
|
|
26
|
+
): HTMLDivElement {
|
|
27
|
+
const element = document.createElement("div");
|
|
28
|
+
element.className = className;
|
|
29
|
+
parent.append(element);
|
|
30
|
+
return element;
|
|
31
|
+
}
|
data/yarn.lock
CHANGED
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
minimatch "^3.0.4"
|
|
18
18
|
strip-json-comments "^3.1.1"
|
|
19
19
|
|
|
20
|
+
"@hotwired/stimulus@^3.0.1":
|
|
21
|
+
version "3.0.1"
|
|
22
|
+
resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.0.1.tgz#141f15645acaa3b133b7c247cad58ae252ffae85"
|
|
23
|
+
integrity sha512-oHsJhgY2cip+K2ED7vKUNd2P+BEswVhrCYcJ802DSsblJFv7mPFVk3cQKvm2vHgHeDVdnj7oOKrBbzp1u8D+KA==
|
|
24
|
+
|
|
20
25
|
"@humanwhocodes/config-array@^0.9.2":
|
|
21
26
|
version "0.9.2"
|
|
22
27
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914"
|
|
@@ -52,6 +57,11 @@
|
|
|
52
57
|
"@nodelib/fs.scandir" "2.1.5"
|
|
53
58
|
fastq "^1.6.0"
|
|
54
59
|
|
|
60
|
+
"@popperjs/core@^2.11.0":
|
|
61
|
+
version "2.11.0"
|
|
62
|
+
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.0.tgz#6734f8ebc106a0860dff7f92bf90df193f0935d7"
|
|
63
|
+
integrity sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ==
|
|
64
|
+
|
|
55
65
|
"@rails/request.js@^0.0.6":
|
|
56
66
|
version "0.0.6"
|
|
57
67
|
resolved "https://registry.yarnpkg.com/@rails/request.js/-/request.js-0.0.6.tgz#5f0347a9f363e50ec45118c7134080490cda81d8"
|
metadata
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shimmer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jens Ravens
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-12-
|
|
11
|
+
date: 2021-12-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
|
-
description:
|
|
13
|
+
description:
|
|
14
14
|
email:
|
|
15
15
|
- jens@nerdgeschoss.de
|
|
16
16
|
executables: []
|
|
@@ -48,12 +48,14 @@ files:
|
|
|
48
48
|
- lib/shimmer/version.rb
|
|
49
49
|
- package.json
|
|
50
50
|
- rollup.config.js
|
|
51
|
-
-
|
|
51
|
+
- src/controllers/remote-navigation.ts
|
|
52
52
|
- src/index.ts
|
|
53
53
|
- src/locale.ts
|
|
54
54
|
- src/modal.ts
|
|
55
|
+
- src/popover.ts
|
|
55
56
|
- src/serviceworker.ts
|
|
56
57
|
- src/touch.ts
|
|
58
|
+
- src/util.ts
|
|
57
59
|
- tsconfig.json
|
|
58
60
|
- typings.d.ts
|
|
59
61
|
- yarn.lock
|
|
@@ -63,7 +65,7 @@ licenses:
|
|
|
63
65
|
metadata:
|
|
64
66
|
homepage_uri: https://github.com/nerdgeschoss/shimmer
|
|
65
67
|
source_code_uri: https://github.com/nerdgeschoss/shimmer
|
|
66
|
-
post_install_message:
|
|
68
|
+
post_install_message:
|
|
67
69
|
rdoc_options: []
|
|
68
70
|
require_paths:
|
|
69
71
|
- lib
|
|
@@ -79,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
79
81
|
version: '0'
|
|
80
82
|
requirements: []
|
|
81
83
|
rubygems_version: 3.2.32
|
|
82
|
-
signing_key:
|
|
84
|
+
signing_key:
|
|
83
85
|
specification_version: 4
|
|
84
86
|
summary: Shimmer brings all the bells and whistles of a hotwired application, right
|
|
85
87
|
from the start.
|
data/shimmer.gemspec
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "lib/shimmer/version"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "shimmer"
|
|
7
|
-
spec.version = Shimmer::VERSION
|
|
8
|
-
spec.authors = ["Jens Ravens"]
|
|
9
|
-
spec.email = ["jens@nerdgeschoss.de"]
|
|
10
|
-
|
|
11
|
-
spec.summary = "Shimmer brings all the bells and whistles of a hotwired application, right from the start."
|
|
12
|
-
spec.homepage = "https://github.com/nerdgeschoss/shimmer"
|
|
13
|
-
spec.license = "MIT"
|
|
14
|
-
spec.required_ruby_version = ">= 2.6.0"
|
|
15
|
-
|
|
16
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
17
|
-
spec.metadata["source_code_uri"] = spec.homepage
|
|
18
|
-
|
|
19
|
-
# Specify which files should be added to the gem when it is released.
|
|
20
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
21
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
22
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
23
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
spec.bindir = "exe"
|
|
27
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
28
|
-
spec.require_paths = ["lib"]
|
|
29
|
-
|
|
30
|
-
# Uncomment to register a new dependency of your gem
|
|
31
|
-
# spec.add_dependency "example-gem", "~> 1.0"
|
|
32
|
-
|
|
33
|
-
# For more information and examples about making a new gem, checkout our
|
|
34
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
|
35
|
-
end
|