playbook_ui 17.0.0 → 17.1.0.pre.rc.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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_button/docs/_button_reaction.html.erb +1 -1
- data/app/pb_kits/playbook/pb_button/docs/_button_reaction.jsx +1 -1
- data/app/pb_kits/playbook/pb_button/docs/_button_reaction.md +1 -1
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_error.html.erb +1 -1
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_error.jsx +1 -4
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_error.html.erb +1 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_error.jsx +1 -4
- data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.html.erb +1 -1
- data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.jsx +1 -6
- data/app/pb_kits/playbook/pb_icon/docs/_icon_custom.html.erb +6 -7
- data/app/pb_kits/playbook/pb_icon/docs/_icon_custom.md +1 -1
- data/app/pb_kits/playbook/pb_icon/icon.html.erb +1 -1
- data/app/pb_kits/playbook/pb_icon/icon.rb +41 -17
- data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_emoji.html.erb +3 -3
- data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_emoji.jsx +2 -2
- data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_emoji.md +1 -1
- data/app/pb_kits/playbook/pb_icon_circle/icon_circle.test.js +1 -1
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.jsx +1 -2
- data/app/pb_kits/playbook/pb_select/_select.scss +6 -0
- data/app/pb_kits/playbook/pb_select/docs/_select_error.html.erb +1 -1
- data/app/pb_kits/playbook/pb_select/docs/_select_error.jsx +2 -7
- data/app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_custom.html.erb +3 -3
- data/app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_custom.md +1 -1
- data/app/pb_kits/playbook/pb_table/_table.tsx +4 -0
- data/app/pb_kits/playbook/pb_table/docs/_playground.json +2 -0
- data/app/pb_kits/playbook/pb_table/docs/_playground.overrides.json +1 -1
- data/app/pb_kits/playbook/pb_table/docs/_sections.yml +1 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_contrast_border.html.erb +71 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_contrast_border.jsx +93 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_contrast_border.md +1 -0
- data/app/pb_kits/playbook/pb_table/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_table/kit.schema.json +8 -0
- data/app/pb_kits/playbook/pb_table/styles/_all.scss +2 -1
- data/app/pb_kits/playbook/pb_table/styles/_contrast_border.scss +87 -0
- data/app/pb_kits/playbook/pb_table/styles/_desktop_collapse.scss +2 -2
- data/app/pb_kits/playbook/pb_table/styles/_headers.scss +3 -3
- data/app/pb_kits/playbook/pb_table/styles/_hover.scss +2 -2
- data/app/pb_kits/playbook/pb_table/styles/_mobile.scss +2 -2
- data/app/pb_kits/playbook/pb_table/styles/_mobile_collapse.scss +2 -2
- data/app/pb_kits/playbook/pb_table/styles/_scroll.scss +2 -2
- data/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss +2 -2
- data/app/pb_kits/playbook/pb_table/styles/_structure.scss +1 -1
- data/app/pb_kits/playbook/pb_table/styles/_table-card.scss +2 -2
- data/app/pb_kits/playbook/pb_table/styles/_tablet_collapse.scss +2 -2
- data/app/pb_kits/playbook/pb_table/styles/_vertical_border.scss +9 -9
- data/app/pb_kits/playbook/pb_table/table.rb +7 -1
- data/app/pb_kits/playbook/pb_table/table.test.js +5 -0
- data/app/pb_kits/playbook/pb_text_input/docs/_text_input_error.html.erb +1 -1
- data/app/pb_kits/playbook/pb_text_input/docs/_text_input_error.jsx +1 -8
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_error.html.erb +1 -1
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_error.jsx +1 -7
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_error_state.jsx +2 -6
- data/dist/chunks/_detail-DmbtP8Zd.js +5 -0
- data/dist/chunks/{_pb_line_graph-B3q4LKEz.js → _pb_line_graph-BynhzAZz.js} +1 -1
- data/dist/chunks/_table-BKJZFT_d.js +1 -0
- data/dist/chunks/_typeahead-CV5P_leb.js +1 -0
- data/dist/chunks/{globalProps-zGbN4oBH.js → globalProps-BmtRVofv.js} +1 -1
- data/dist/chunks/lib-CYZytrqW.js +29 -0
- data/dist/chunks/vendor.js +3 -3
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +2 -2
- metadata +12 -8
- data/dist/chunks/_detail-BKKHcGcj.js +0 -5
- data/dist/chunks/_table-Bkla2kcQ.js +0 -1
- data/dist/chunks/_typeahead-CULhE-SU.js +0 -1
- data/dist/chunks/lib-LNv9xZ-1.js +0 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7b715350921a0d13054afef8c7a265256206ce8a191121ac5a553f7a6c53f81e
|
|
4
|
+
data.tar.gz: d2f45143b6d02498ee81758e82ce67ad49f35d821990d627bdd973ac3d944f83
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 060ba5b0e47cbefc0822b7f624b45344e28dea010f2b0af1d380e7d85e33b59f0b5a2df7153cbc1b4b7264b4821ee9617dc2e732ff8704b029333329119a1583
|
|
7
|
+
data.tar.gz: a90fecaa285e278f7d119e96f48760f8c36816ef7f8810c1177e1100d088bf34c9d4f7705319d99a1106e570b4304989536169262bc5223d2ecb505210ca5566
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= pb_rails("button", props: { count: 153, highlight: false, icon: "
|
|
1
|
+
<%= pb_rails("button", props: { count: 153, highlight: false, icon: "🎉", classname: "count", id: "reaction-button-highlight", variant: "reaction" }) %>
|
|
2
2
|
<%= pb_rails("button", props: { count: 5, icon: "1️⃣", variant: "reaction", margin_left: "lg" }) %>
|
|
3
3
|
<%= pb_rails("button", props: { variant: "reaction", margin_left: "lg" }) %>
|
|
4
4
|
<%= pb_rails("button", props: { icon: "user", variant: "reaction", margin_left: "lg" }) %>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
The `reaction` variant accepts any
|
|
1
|
+
The `reaction` variant accepts any emoji as a string within the `icon` prop. If nothing is passed to the icon prop, the default reaction button will be displayed as seen in the third example. The default reaction button will also be rendered if a Fontawesome icon (not an Emoji) is passed to the `icon` prop of a `reaction` variant, but the default "smiley +" icon will be replaced with the named icon.
|
|
2
2
|
|
|
3
3
|
Reaction buttons also accept two additional (optional) props: `count`, which accepts a number (i.e., a count of reactions) to be displayed next to the Emoji; and `highlight`, which is a boolean that if true, displays the 'active' state for the button. Click the first reaction button to see this in action!
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
|
|
3
3
|
import DatePicker from '../_date_picker'
|
|
4
|
-
import Icon from '../../pb_icon/_icon'
|
|
5
4
|
|
|
6
5
|
const DatePickerError = (props) => (
|
|
7
6
|
<div>
|
|
8
7
|
<DatePicker
|
|
9
|
-
error=
|
|
10
|
-
<Icon icon="warning" /> Invalid date. Please pick a valid date.
|
|
11
|
-
</>}
|
|
8
|
+
error="Invalid date. Please pick a valid date."
|
|
12
9
|
pickerId="date-picker-error"
|
|
13
10
|
{...props}
|
|
14
11
|
/>
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import Dropdown from '../../pb_dropdown/_dropdown'
|
|
3
|
-
import Icon from '../../pb_icon/_icon'
|
|
4
3
|
|
|
5
4
|
const DropdownError = (props) => {
|
|
6
5
|
const [selectedOption, setSelectedOption] = useState()
|
|
7
|
-
const error = selectedOption?.value ? null :
|
|
8
|
-
<Icon icon="warning" /> Please make a valid selection
|
|
9
|
-
</>)
|
|
6
|
+
const error = selectedOption?.value ? null : "Please make a valid selection"
|
|
10
7
|
const options = [
|
|
11
8
|
{
|
|
12
9
|
label: "United States",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<%= pb_rails("file_upload", props: {id: "error", error:
|
|
1
|
+
<%= pb_rails("file_upload", props: {id: "error", error: "Please upload a valid file."}) %>
|
|
@@ -2,7 +2,6 @@ import React, { useState } from 'react'
|
|
|
2
2
|
import FileUpload from '../_file_upload'
|
|
3
3
|
import List from '../../pb_list/_list'
|
|
4
4
|
import ListItem from '../../pb_list/_list_item'
|
|
5
|
-
import Icon from '../../pb_icon/_icon'
|
|
6
5
|
|
|
7
6
|
const AcceptedFilesList = ({ files }) => (
|
|
8
7
|
<List>
|
|
@@ -19,10 +18,6 @@ const FileUploadError = (props) => {
|
|
|
19
18
|
setFilesToUpload([...filesToUpload, ...files])
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
const error = (<>
|
|
23
|
-
<Icon icon="warning" /> Please upload a valid file
|
|
24
|
-
</>)
|
|
25
|
-
|
|
26
21
|
return (
|
|
27
22
|
<div>
|
|
28
23
|
<AcceptedFilesList
|
|
@@ -30,7 +25,7 @@ const FileUploadError = (props) => {
|
|
|
30
25
|
{...props}
|
|
31
26
|
/>
|
|
32
27
|
<FileUpload
|
|
33
|
-
error=
|
|
28
|
+
error="Please upload a valid file."
|
|
34
29
|
onFilesAccepted={handleOnFilesAccepted}
|
|
35
30
|
{...props}
|
|
36
31
|
/>
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<%# SVG fill color inherited from css color property %>
|
|
2
2
|
<div class="icon-wrapper">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<p><%= pb_rails("icon", props: { icon:
|
|
6
|
-
<p><%= pb_rails("icon", props: {
|
|
7
|
-
<p><%= pb_rails("icon", props: {
|
|
8
|
-
<p><%= pb_rails("icon", props: { size: "5x", icon:
|
|
9
|
-
<p><%= pb_rails("icon", props: { flip: "horizontal", size: "5x", icon: svg_url } ) %></p>
|
|
3
|
+
<% svg_path = Playbook::Engine.root.join("app/pb_kits/playbook/utilities/icons/clock.svg").to_s %>
|
|
4
|
+
<p><%= pb_rails("icon", props: { icon: svg_path } ) %></p>
|
|
5
|
+
<p><%= pb_rails("icon", props: { rotation: 90, icon: svg_path, size: "2x" } ) %></p>
|
|
6
|
+
<p><%= pb_rails("icon", props: { spin: true, icon: svg_path, size: "3x" } ) %></p>
|
|
7
|
+
<p><%= pb_rails("icon", props: { size: "5x", icon: svg_path } ) %></p>
|
|
8
|
+
<p><%= pb_rails("icon", props: { flip: "horizontal", size: "5x", icon: svg_path } ) %></p>
|
|
10
9
|
</div>
|
|
@@ -12,4 +12,4 @@ You must source _your own SVG into component/view_ you are working on. This can
|
|
|
12
12
|
|
|
13
13
|
### Rails
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Pass a local filesystem path to an SVG under your application or a mounted engine (for example `Playbook::Engine.root.join("app/pb_kits/playbook/utilities/icons/clock.svg").to_s`) via the `icon` or `custom_icon` prop. Remote `http(s)` URLs are not fetched — only local / engine paths are supported.
|
|
@@ -46,8 +46,19 @@ module Playbook
|
|
|
46
46
|
prop :tabindex
|
|
47
47
|
|
|
48
48
|
def valid_emoji?
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
str = icon.to_s
|
|
50
|
+
return false if str.blank?
|
|
51
|
+
# Digits / # / * match \p{Emoji} as keycap bases; require real emoji forms.
|
|
52
|
+
# Also reject markup so we never treat HTML-like strings as emoji.
|
|
53
|
+
return false if str.match?(%r{[<>&"'A-Za-z/\\]})
|
|
54
|
+
|
|
55
|
+
str.match?(
|
|
56
|
+
/
|
|
57
|
+
\p{Emoji_Presentation}
|
|
58
|
+
| \p{Extended_Pictographic}
|
|
59
|
+
| [\d#*]\u{FE0F}?\u{20E3}
|
|
60
|
+
/x
|
|
61
|
+
)
|
|
51
62
|
end
|
|
52
63
|
|
|
53
64
|
def classname
|
|
@@ -103,7 +114,11 @@ module Playbook
|
|
|
103
114
|
if Rails.application.config.respond_to?(:icon_path)
|
|
104
115
|
resolved_icon = resolve_alias(icon)
|
|
105
116
|
path = self.class.icon_path_index[resolved_icon]
|
|
106
|
-
|
|
117
|
+
# icon_path_index keys off the *.svg basename, so apply the same
|
|
118
|
+
# realpath / .svg / allowed-root checks as custom_icon loading —
|
|
119
|
+
# otherwise a foo.svg symlink to a non-svg file would be File.read
|
|
120
|
+
# directly in svg_content.
|
|
121
|
+
path && File.exist?(path) ? allowed_svg_path(path)&.to_s : nil
|
|
107
122
|
end
|
|
108
123
|
end
|
|
109
124
|
|
|
@@ -302,8 +317,9 @@ module Playbook
|
|
|
302
317
|
source = source.to_s
|
|
303
318
|
return "" if source.blank?
|
|
304
319
|
|
|
305
|
-
|
|
306
|
-
|
|
320
|
+
# Remote http(s) fetch removed: untrusted custom_icon/icon values must not
|
|
321
|
+
# trigger server-side requests (SSRF). Use local / engine SVG paths only.
|
|
322
|
+
return "" if remote_svg_uri(source)
|
|
307
323
|
|
|
308
324
|
path = allowed_svg_path(source)
|
|
309
325
|
return "" unless path
|
|
@@ -318,16 +334,11 @@ module Playbook
|
|
|
318
334
|
nil
|
|
319
335
|
end
|
|
320
336
|
|
|
321
|
-
def read_remote_svg(uri)
|
|
322
|
-
uri.open("User-Agent" => "Playbook-Icon-Kit/1.0 (https://github.com/powerhome/playbook)", redirect: false, &:read)
|
|
323
|
-
rescue OpenURI::HTTPError, StandardError
|
|
324
|
-
""
|
|
325
|
-
end
|
|
326
|
-
|
|
327
337
|
def allowed_svg_path(source)
|
|
328
338
|
candidate = Pathname.new(source)
|
|
329
339
|
candidate = Rails.root.join(candidate) unless candidate.absolute?
|
|
330
|
-
resolved = candidate.expand_path
|
|
340
|
+
resolved = real_path(candidate.expand_path)
|
|
341
|
+
return nil unless resolved
|
|
331
342
|
return nil unless svg_file?(resolved)
|
|
332
343
|
return nil unless path_within_allowed_root?(resolved)
|
|
333
344
|
|
|
@@ -337,7 +348,8 @@ module Playbook
|
|
|
337
348
|
# Only ever read real .svg files. This keeps non-svg files that happen to
|
|
338
349
|
# live inside an allowed root (config/master.key, credentials, .env, ...)
|
|
339
350
|
# structurally out of the read path rather than relying on the is_svg?
|
|
340
|
-
# gate to exclude them.
|
|
351
|
+
# gate to exclude them. Extension is checked on the resolved real path so
|
|
352
|
+
# a *.svg symlink to a non-svg file cannot bypass the filter.
|
|
341
353
|
def svg_file?(path)
|
|
342
354
|
path.file? && path.extname.casecmp(".svg").zero?
|
|
343
355
|
end
|
|
@@ -351,9 +363,12 @@ module Playbook
|
|
|
351
363
|
false
|
|
352
364
|
end
|
|
353
365
|
|
|
354
|
-
# An SVG may live in the host application
|
|
355
|
-
# (Playbook itself, or a host app's component engines),
|
|
356
|
-
#
|
|
366
|
+
# An SVG may live in the host application, any mounted engine
|
|
367
|
+
# (Playbook itself, or a host app's component engines), or the configured
|
|
368
|
+
# icon_path directory. playbook-website points development icon_path at
|
|
369
|
+
# ../node_modules/@powerhome/playbook-icons/icons, which resolves outside
|
|
370
|
+
# Rails.root / Engine.root — that directory must still be allowed, while
|
|
371
|
+
# realpath + svg_file? keep symlink-to-non-svg blocked.
|
|
357
372
|
def allowed_svg_roots
|
|
358
373
|
@allowed_svg_roots ||= svg_root_candidates.filter_map { |candidate| real_path(candidate) }.uniq
|
|
359
374
|
end
|
|
@@ -361,10 +376,19 @@ module Playbook
|
|
|
361
376
|
def svg_root_candidates
|
|
362
377
|
Rails::Engine.descendants
|
|
363
378
|
.map { |engine| engine_root(engine) }
|
|
364
|
-
.push(Playbook::Engine.root, Rails.root)
|
|
379
|
+
.push(Playbook::Engine.root, Rails.root, configured_icon_path_root)
|
|
365
380
|
.compact
|
|
366
381
|
end
|
|
367
382
|
|
|
383
|
+
def configured_icon_path_root
|
|
384
|
+
return unless Rails.application.config.respond_to?(:icon_path)
|
|
385
|
+
|
|
386
|
+
base = Rails.application.config.icon_path
|
|
387
|
+
return if base.blank?
|
|
388
|
+
|
|
389
|
+
Rails.root.join(base)
|
|
390
|
+
end
|
|
391
|
+
|
|
368
392
|
def engine_root(engine)
|
|
369
393
|
engine.root
|
|
370
394
|
rescue
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
}) %>
|
|
5
5
|
<br />
|
|
6
6
|
<%= pb_rails("icon_circle", props: {
|
|
7
|
-
icon: "
|
|
7
|
+
icon: "😍",
|
|
8
8
|
size:"md",
|
|
9
9
|
variant: "red"
|
|
10
10
|
}) %>
|
|
11
11
|
<br />
|
|
12
12
|
<%= pb_rails("icon_circle", props: {
|
|
13
|
-
icon:
|
|
13
|
+
icon: "🎉",
|
|
14
14
|
size: "lg",
|
|
15
15
|
variant: "teal"
|
|
16
|
-
}) %>
|
|
16
|
+
}) %>
|
|
@@ -12,14 +12,14 @@ const IconCircleEmoji = (props) => {
|
|
|
12
12
|
/>
|
|
13
13
|
<br/>
|
|
14
14
|
<IconCircle
|
|
15
|
-
icon="
|
|
15
|
+
icon="😍"
|
|
16
16
|
size="md"
|
|
17
17
|
variant="red"
|
|
18
18
|
{...props}
|
|
19
19
|
/>
|
|
20
20
|
<br/>
|
|
21
21
|
<IconCircle
|
|
22
|
-
icon="
|
|
22
|
+
icon="🎉"
|
|
23
23
|
size="lg"
|
|
24
24
|
variant="teal"
|
|
25
25
|
{...props}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
The Icon Circle also allows you to pass
|
|
1
|
+
The Icon Circle also allows you to pass an emoji in place of an icon if needed. Pass any emoji as a string to the `icon` prop as shown in the code snippet below.
|
|
@@ -3,7 +3,6 @@ import React, { useEffect, useState } from "react";
|
|
|
3
3
|
import Button from '../../pb_button/_button'
|
|
4
4
|
import FixedConfirmationToast from '../../pb_fixed_confirmation_toast/_fixed_confirmation_toast'
|
|
5
5
|
import PhoneNumberInput from '../../pb_phone_number_input/_phone_number_input'
|
|
6
|
-
import Icon from '../../pb_icon/_icon'
|
|
7
6
|
|
|
8
7
|
const PhoneNumberInputValidation = (props) => {
|
|
9
8
|
const [formErrors, setFormErrors] = useState("");
|
|
@@ -16,7 +15,7 @@ const PhoneNumberInputValidation = (props) => {
|
|
|
16
15
|
// Start with initial error - will be cleared on blur if valid
|
|
17
16
|
const initialError = (
|
|
18
17
|
<>
|
|
19
|
-
|
|
18
|
+
Missing phone number.
|
|
20
19
|
</>
|
|
21
20
|
);
|
|
22
21
|
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
overflow: hidden;
|
|
19
19
|
text-overflow: ellipsis;
|
|
20
20
|
max-height: 45px;
|
|
21
|
+
&:has(option[value=""]:checked) {
|
|
22
|
+
color: $input_text_default;
|
|
23
|
+
}
|
|
21
24
|
@media (hover:hover) {
|
|
22
25
|
&:hover, &:active, &:focus {
|
|
23
26
|
background-color: $input_background_state;
|
|
@@ -170,6 +173,9 @@
|
|
|
170
173
|
white-space: nowrap;
|
|
171
174
|
overflow: hidden;
|
|
172
175
|
text-overflow: ellipsis;
|
|
176
|
+
&:has(option[value=""]:checked) {
|
|
177
|
+
color: $input_text_default_dark;
|
|
178
|
+
}
|
|
173
179
|
@media (hover:hover) {
|
|
174
180
|
&:hover, &:active, &:focus {
|
|
175
181
|
background-color: $input_background_state_dark;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import Body from '../../pb_body/_body'
|
|
3
3
|
import Select from '../../pb_select/_select'
|
|
4
|
-
import Icon from '../../pb_icon/_icon'
|
|
5
4
|
|
|
6
5
|
const SelectError = (props) => {
|
|
7
6
|
const options = [
|
|
@@ -19,14 +18,10 @@ const SelectError = (props) => {
|
|
|
19
18
|
},
|
|
20
19
|
]
|
|
21
20
|
|
|
22
|
-
const error = (<>
|
|
23
|
-
<Icon icon="warning" /> Please make a valid selection
|
|
24
|
-
</>)
|
|
25
|
-
|
|
26
21
|
return (
|
|
27
22
|
<div>
|
|
28
23
|
<Select
|
|
29
|
-
error=
|
|
24
|
+
error="Please make a valid selection"
|
|
30
25
|
label="Favorite Food"
|
|
31
26
|
name="food-error"
|
|
32
27
|
options={options}
|
|
@@ -34,7 +29,7 @@ const SelectError = (props) => {
|
|
|
34
29
|
{...props}
|
|
35
30
|
/>
|
|
36
31
|
<Body
|
|
37
|
-
error=
|
|
32
|
+
error="Please make a valid selection"
|
|
38
33
|
status="negative"
|
|
39
34
|
{...props}
|
|
40
35
|
/>
|
data/app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_custom.html.erb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<div class="pb--doc-demo-row">
|
|
2
|
-
<%
|
|
2
|
+
<% svg_path = Playbook::Engine.root.join("app/pb_kits/playbook/utilities/icons/clock.svg").to_s %>
|
|
3
3
|
|
|
4
4
|
<%= pb_rails("selectable_card_icon", props: {
|
|
5
|
-
custom_icon:
|
|
5
|
+
custom_icon: svg_path,
|
|
6
6
|
title_text: "Customization",
|
|
7
7
|
body_text: "Personalize everything",
|
|
8
8
|
input_id: 1,
|
|
9
9
|
checked: true,
|
|
10
10
|
}) %>
|
|
11
|
-
</div>
|
|
11
|
+
</div>
|
|
@@ -16,4 +16,4 @@ So long as you have a valid React `<SVG>` node, you can send it as the `customIc
|
|
|
16
16
|
|
|
17
17
|
### Rails
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Pass a local filesystem path to an SVG under your application or a mounted engine (for example `Playbook::Engine.root.join("app/pb_kits/playbook/utilities/icons/clock.svg").to_s`) via the `custom_icon` prop. Remote `http(s)` URLs are not fetched — only local / engine paths are supported.
|
|
@@ -45,6 +45,7 @@ type TableProps = {
|
|
|
45
45
|
title?: string,
|
|
46
46
|
titleProps?: { [key: string]: any },
|
|
47
47
|
variant?: "default" | "withFilter",
|
|
48
|
+
contrastBorder?: boolean,
|
|
48
49
|
verticalBorder?: boolean,
|
|
49
50
|
} & GlobalProps
|
|
50
51
|
|
|
@@ -80,6 +81,7 @@ const Table = (props: TableProps): React.ReactElement => {
|
|
|
80
81
|
striped = false,
|
|
81
82
|
tag = 'table',
|
|
82
83
|
title,
|
|
84
|
+
contrastBorder = false,
|
|
83
85
|
verticalBorder = false,
|
|
84
86
|
} = props
|
|
85
87
|
|
|
@@ -87,6 +89,7 @@ const Table = (props: TableProps): React.ReactElement => {
|
|
|
87
89
|
const dataProps = buildDataProps(data)
|
|
88
90
|
const htmlProps = buildHtmlProps(htmlOptions)
|
|
89
91
|
const tableCollapseCss = responsive !== 'none' ? `table-collapse-${collapse}` : ''
|
|
92
|
+
const contrastBorderCss = contrastBorder ? 'contrast-border' : ''
|
|
90
93
|
const verticalBorderCss = verticalBorder ? 'vertical-border' : ''
|
|
91
94
|
const spaceCssName = outerPadding !== 'none' ? 'space_' : ''
|
|
92
95
|
const outerPaddingCss = outerPadding ? `outer_padding_${spaceCssName}${outerPadding}` : ''
|
|
@@ -117,6 +120,7 @@ const Table = (props: TableProps): React.ReactElement => {
|
|
|
117
120
|
},
|
|
118
121
|
globalProps(props),
|
|
119
122
|
tableCollapseCss,
|
|
123
|
+
contrastBorderCss,
|
|
120
124
|
verticalBorderCss,
|
|
121
125
|
className
|
|
122
126
|
)
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"striped": false,
|
|
15
15
|
"tag": "table",
|
|
16
16
|
"variant": "default",
|
|
17
|
+
"contrastBorder": false,
|
|
17
18
|
"verticalBorder": false
|
|
18
19
|
},
|
|
19
20
|
"groups": [
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"props": [
|
|
34
35
|
"striped",
|
|
35
36
|
"verticalBorder",
|
|
37
|
+
"contrastBorder",
|
|
36
38
|
"singleLine",
|
|
37
39
|
"disableHover",
|
|
38
40
|
"headerStyle",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"name": "Appearance",
|
|
42
|
-
"props": ["striped", "verticalBorder", "singleLine", "disableHover", "headerStyle", "dark", "dataTable"]
|
|
42
|
+
"props": ["striped", "verticalBorder", "contrastBorder", "singleLine", "disableHover", "headerStyle", "dark", "dataTable"]
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"name": "Sticky Columns",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<%= pb_rails("table", props: { size: "sm", contrast_border: true }) do %>
|
|
2
|
+
<thead>
|
|
3
|
+
<tr>
|
|
4
|
+
<th>Column 1</th>
|
|
5
|
+
<th>Column 2</th>
|
|
6
|
+
<th>Column 3</th>
|
|
7
|
+
<th>Column 4</th>
|
|
8
|
+
<th>Column 5</th>
|
|
9
|
+
</tr>
|
|
10
|
+
</thead>
|
|
11
|
+
<tbody>
|
|
12
|
+
<tr>
|
|
13
|
+
<td>Value 1</td>
|
|
14
|
+
<td>Value 2</td>
|
|
15
|
+
<td>Value 3</td>
|
|
16
|
+
<td>Value 4</td>
|
|
17
|
+
<td>Value 5</td>
|
|
18
|
+
</tr>
|
|
19
|
+
<tr>
|
|
20
|
+
<td>Value 1</td>
|
|
21
|
+
<td>Value 2</td>
|
|
22
|
+
<td>Value 3</td>
|
|
23
|
+
<td>Value 4</td>
|
|
24
|
+
<td>Value 5</td>
|
|
25
|
+
</tr>
|
|
26
|
+
<tr>
|
|
27
|
+
<td>Value 1</td>
|
|
28
|
+
<td>Value 2</td>
|
|
29
|
+
<td>Value 3</td>
|
|
30
|
+
<td>Value 4</td>
|
|
31
|
+
<td>Value 5</td>
|
|
32
|
+
</tr>
|
|
33
|
+
</tbody>
|
|
34
|
+
<% end %>
|
|
35
|
+
|
|
36
|
+
<br/>
|
|
37
|
+
|
|
38
|
+
<%= pb_rails("table", props: { size: "sm", contrast_border: true, vertical_border: true }) do %>
|
|
39
|
+
<thead>
|
|
40
|
+
<tr>
|
|
41
|
+
<th>Column 1</th>
|
|
42
|
+
<th>Column 2</th>
|
|
43
|
+
<th>Column 3</th>
|
|
44
|
+
<th>Column 4</th>
|
|
45
|
+
<th>Column 5</th>
|
|
46
|
+
</tr>
|
|
47
|
+
</thead>
|
|
48
|
+
<tbody>
|
|
49
|
+
<tr>
|
|
50
|
+
<td>Value 1</td>
|
|
51
|
+
<td>Value 2</td>
|
|
52
|
+
<td>Value 3</td>
|
|
53
|
+
<td>Value 4</td>
|
|
54
|
+
<td>Value 5</td>
|
|
55
|
+
</tr>
|
|
56
|
+
<tr>
|
|
57
|
+
<td>Value 1</td>
|
|
58
|
+
<td>Value 2</td>
|
|
59
|
+
<td>Value 3</td>
|
|
60
|
+
<td>Value 4</td>
|
|
61
|
+
<td>Value 5</td>
|
|
62
|
+
</tr>
|
|
63
|
+
<tr>
|
|
64
|
+
<td>Value 1</td>
|
|
65
|
+
<td>Value 2</td>
|
|
66
|
+
<td>Value 3</td>
|
|
67
|
+
<td>Value 4</td>
|
|
68
|
+
<td>Value 5</td>
|
|
69
|
+
</tr>
|
|
70
|
+
</tbody>
|
|
71
|
+
<% end %>
|