mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-28 01:45:20 +03:00
Merge branch 'master' into dansby/put-litter-in-its-place
This commit is contained in:
commit
97c8a9fc7b
@ -5,7 +5,10 @@ Nri.Ui.Menu.V1,upgrade to V3
|
||||
Nri.Ui.Menu.V2,upgrade to V3
|
||||
Nri.Ui.Modal.V10,upgrade to V11
|
||||
Nri.Ui.RadioButton.V1,upgrade to V2
|
||||
Nri.Ui.Select.V5,upgrade to V7
|
||||
Nri.Ui.Select.V5,upgrade to V8
|
||||
Nri.Ui.Select.V7,upgrade to V8
|
||||
Nri.Ui.Table.V4,upgrade to V5
|
||||
Nri.Ui.Tabs.V6,upgrade to V7
|
||||
Nri.Ui.Text.V5,upgrade to V6
|
||||
Nri.Ui.TextInput.V6,upgrade to V7
|
||||
Nri.Ui.Tooltip.V1,upgrade to V2
|
||||
|
|
5
elm.json
5
elm.json
@ -3,7 +3,7 @@
|
||||
"name": "NoRedInk/noredink-ui",
|
||||
"summary": "UI Widgets we use at NRI",
|
||||
"license": "BSD-3-Clause",
|
||||
"version": "14.6.0",
|
||||
"version": "14.9.0",
|
||||
"exposed-modules": [
|
||||
"Nri.Ui",
|
||||
"Nri.Ui.Accordion.V1",
|
||||
@ -51,6 +51,7 @@
|
||||
"Nri.Ui.SegmentedControl.V14",
|
||||
"Nri.Ui.Select.V5",
|
||||
"Nri.Ui.Select.V7",
|
||||
"Nri.Ui.Select.V8",
|
||||
"Nri.Ui.Slide.V1",
|
||||
"Nri.Ui.SlideModal.V2",
|
||||
"Nri.Ui.SortableTable.V2",
|
||||
@ -61,9 +62,11 @@
|
||||
"Nri.Ui.Tabs.V6",
|
||||
"Nri.Ui.Tabs.V7",
|
||||
"Nri.Ui.Text.V5",
|
||||
"Nri.Ui.Text.V6",
|
||||
"Nri.Ui.Text.Writing.V1",
|
||||
"Nri.Ui.TextArea.V4",
|
||||
"Nri.Ui.TextInput.V6",
|
||||
"Nri.Ui.TextInput.V7",
|
||||
"Nri.Ui.Tooltip.V1",
|
||||
"Nri.Ui.Tooltip.V2",
|
||||
"Nri.Ui.UiIcon.V1"
|
||||
|
@ -33,11 +33,7 @@ hint = 'Use Accessibility.Widgetd.Widget'
|
||||
|
||||
[forbidden.Html]
|
||||
hint = 'Use Html.Styled'
|
||||
usages = [
|
||||
'styleguide-app/../src/Nri/Ui/Button/V8.elm',
|
||||
'styleguide-app/Examples/Modal.elm',
|
||||
'styleguide-app/Main.elm',
|
||||
]
|
||||
usages = ['styleguide-app/../src/Nri/Ui/Button/V8.elm']
|
||||
|
||||
[forbidden."Nri.Ui.Accordion.V1"]
|
||||
hint = 'upgrade to V3'
|
||||
@ -95,7 +91,10 @@ hint = 'upgrade to V14'
|
||||
hint = 'upgrade to V14'
|
||||
|
||||
[forbidden."Nri.Ui.Select.V5"]
|
||||
hint = 'upgrade to V7'
|
||||
hint = 'upgrade to V8'
|
||||
|
||||
[forbidden."Nri.Ui.Select.V7"]
|
||||
hint = 'upgrade to V8'
|
||||
|
||||
[forbidden."Nri.Ui.Table.V4"]
|
||||
hint = 'upgrade to V5'
|
||||
@ -122,6 +121,12 @@ usages = [
|
||||
'styleguide-app/Examples/Tooltip.elm',
|
||||
]
|
||||
|
||||
[forbidden."Nri.Ui.Text.V5"]
|
||||
hint = 'upgrade to V6'
|
||||
|
||||
[forbidden."Nri.Ui.TextInput.V6"]
|
||||
hint = 'upgrade to V7'
|
||||
|
||||
[forbidden."Nri.Ui.Tooltip.V1"]
|
||||
hint = 'upgrade to V2'
|
||||
usages = ['styleguide-app/../src/Nri/Ui/Menu/V1.elm']
|
||||
|
462
package-lock.json
generated
462
package-lock.json
generated
@ -394,6 +394,15 @@
|
||||
"winston": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"agent-base": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
|
||||
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es6-promisify": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||
@ -406,6 +415,120 @@
|
||||
"shebang-command": "^1.2.0",
|
||||
"which": "^1.2.9"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"extract-zip": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
|
||||
"integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"concat-stream": "^1.6.2",
|
||||
"debug": "^2.6.9",
|
||||
"mkdirp": "^0.5.4",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
|
||||
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"agent-base": "^4.3.0",
|
||||
"debug": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"puppeteer": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz",
|
||||
"integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.0",
|
||||
"extract-zip": "^1.6.6",
|
||||
"https-proxy-agent": "^2.2.1",
|
||||
"mime": "^2.0.3",
|
||||
"progress": "^2.0.1",
|
||||
"proxy-from-env": "^1.0.0",
|
||||
"rimraf": "^2.6.1",
|
||||
"ws": "^6.1.0"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
|
||||
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -435,6 +558,11 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/mime-types": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.1.tgz",
|
||||
"integrity": "sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw=="
|
||||
},
|
||||
"@types/minimatch": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||
@ -444,8 +572,16 @@
|
||||
"@types/node": {
|
||||
"version": "12.12.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.7.tgz",
|
||||
"integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w=="
|
||||
},
|
||||
"@types/yauzl": {
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz",
|
||||
"integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"JSONStream": {
|
||||
"version": "1.3.4",
|
||||
@ -511,12 +647,9 @@
|
||||
}
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
|
||||
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
|
||||
"requires": {
|
||||
"es6-promisify": "^5.0.0"
|
||||
}
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
|
||||
"integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g=="
|
||||
},
|
||||
"ansi-escapes": {
|
||||
"version": "3.2.0",
|
||||
@ -648,7 +781,8 @@
|
||||
"async-limiter": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
|
||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
|
||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
@ -669,9 +803,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"axe-core": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-3.3.0.tgz",
|
||||
"integrity": "sha512-54XaTd2VB7A6iBnXMUG2LnBOI7aRbnrVxC5Tz+rVUwYl9MX/cIJc/Ll32YUoFIE/e9UKWMZoQenQu9dFrQyZCg=="
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-3.5.3.tgz",
|
||||
"integrity": "sha512-HZpLE7xu05+8AbpqXITGdxp1Xwk8ysAXrg7MiKRY27py3DAyEJpoJQo1727pWF3F+O79V3r+cTWhOzfB49P89w=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.19.0",
|
||||
@ -699,8 +833,7 @@
|
||||
"base64-js": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
|
||||
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.2",
|
||||
@ -711,6 +844,52 @@
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"requires": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz",
|
||||
@ -932,16 +1111,21 @@
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-js": "^1.0.2",
|
||||
"ieee754": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI="
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
},
|
||||
"buffer-xor": {
|
||||
"version": "1.0.3",
|
||||
@ -1007,6 +1191,11 @@
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
|
||||
"dev": true
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
||||
},
|
||||
"cipher-base": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
|
||||
@ -1208,6 +1397,7 @@
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
@ -1266,7 +1456,8 @@
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true
|
||||
},
|
||||
"cors": {
|
||||
"version": "2.8.5",
|
||||
@ -1373,6 +1564,7 @@
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
@ -1558,6 +1750,14 @@
|
||||
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
|
||||
"dev": true
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"requires": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"env-variable": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz",
|
||||
@ -1576,7 +1776,8 @@
|
||||
"es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
|
||||
"dev": true
|
||||
},
|
||||
"es6-promise-pool": {
|
||||
"version": "2.5.0",
|
||||
@ -1588,6 +1789,7 @@
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es6-promise": "^4.0.3"
|
||||
}
|
||||
@ -1691,14 +1893,29 @@
|
||||
"dev": true
|
||||
},
|
||||
"extract-zip": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
|
||||
"integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
|
||||
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
|
||||
"requires": {
|
||||
"concat-stream": "1.6.2",
|
||||
"debug": "2.6.9",
|
||||
"mkdirp": "0.5.1",
|
||||
"yauzl": "2.4.1"
|
||||
"@types/yauzl": "^2.9.1",
|
||||
"debug": "^4.1.1",
|
||||
"get-stream": "^5.1.0",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"extsprintf": {
|
||||
@ -1801,9 +2018,9 @@
|
||||
}
|
||||
},
|
||||
"fd-slicer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
|
||||
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
|
||||
"requires": {
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
@ -1884,6 +2101,11 @@
|
||||
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
|
||||
"dev": true
|
||||
},
|
||||
"fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@ -1907,6 +2129,14 @@
|
||||
"integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"requires": {
|
||||
"pump": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
@ -2093,20 +2323,20 @@
|
||||
"dev": true
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
|
||||
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
|
||||
"integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
|
||||
"requires": {
|
||||
"agent-base": "^4.3.0",
|
||||
"debug": "^3.1.0"
|
||||
"agent-base": "5",
|
||||
"debug": "4"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
@ -2134,8 +2364,7 @@
|
||||
"ieee754": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz",
|
||||
"integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA=="
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.1.4",
|
||||
@ -2274,7 +2503,8 @@
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
@ -2500,9 +2730,9 @@
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
|
||||
"integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA=="
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
|
||||
"integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.36.0",
|
||||
@ -2549,6 +2779,7 @@
|
||||
"version": "0.5.1",
|
||||
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
},
|
||||
@ -2556,10 +2787,16 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
|
||||
},
|
||||
"module-deps": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.1.0.tgz",
|
||||
@ -2586,7 +2823,8 @@
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.2",
|
||||
@ -2807,7 +3045,8 @@
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"dev": true
|
||||
},
|
||||
"progress": {
|
||||
"version": "2.0.3",
|
||||
@ -2825,9 +3064,9 @@
|
||||
}
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
|
||||
"integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4="
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.1.29",
|
||||
@ -2848,6 +3087,15 @@
|
||||
"randombytes": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"requires": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
@ -2855,26 +3103,43 @@
|
||||
"dev": true
|
||||
},
|
||||
"puppeteer": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz",
|
||||
"integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-3.0.0.tgz",
|
||||
"integrity": "sha512-ArmIS8w+XhL4KGP05kxMousA9SFxmeirMkNNcVe5LjK4iGCbZ8qKnG4byuXMru7Ty7a9QwiMUIf80X+zmJuf2A==",
|
||||
"requires": {
|
||||
"@types/mime-types": "^2.1.0",
|
||||
"debug": "^4.1.0",
|
||||
"extract-zip": "^1.6.6",
|
||||
"https-proxy-agent": "^2.2.1",
|
||||
"extract-zip": "^2.0.0",
|
||||
"https-proxy-agent": "^4.0.0",
|
||||
"mime": "^2.0.3",
|
||||
"mime-types": "^2.1.25",
|
||||
"progress": "^2.0.1",
|
||||
"proxy-from-env": "^1.0.0",
|
||||
"rimraf": "^2.6.1",
|
||||
"ws": "^6.1.0"
|
||||
"rimraf": "^3.0.2",
|
||||
"tar-fs": "^2.0.0",
|
||||
"unbzip2-stream": "^1.3.3",
|
||||
"ws": "^7.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.50.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz",
|
||||
"integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.33",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz",
|
||||
"integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==",
|
||||
"requires": {
|
||||
"mime-db": "1.50.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
@ -2961,6 +3226,7 @@
|
||||
"version": "2.3.6",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
@ -3075,11 +3341,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"requires": {
|
||||
"glob": "^7.0.5"
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
},
|
||||
"ripemd160": {
|
||||
@ -3416,6 +3682,41 @@
|
||||
"acorn-node": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"tar-fs": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
|
||||
"integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
|
||||
"requires": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"requires": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"text-hex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||
@ -3425,8 +3726,7 @@
|
||||
"through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
|
||||
},
|
||||
"through2": {
|
||||
"version": "2.0.3",
|
||||
@ -3537,7 +3837,8 @@
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||
"dev": true
|
||||
},
|
||||
"umd": {
|
||||
"version": "3.0.3",
|
||||
@ -3545,6 +3846,15 @@
|
||||
"integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==",
|
||||
"dev": true
|
||||
},
|
||||
"unbzip2-stream": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
|
||||
"integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
|
||||
"requires": {
|
||||
"buffer": "^5.2.1",
|
||||
"through": "^2.3.8"
|
||||
}
|
||||
},
|
||||
"undeclared-identifiers": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz",
|
||||
@ -3734,12 +4044,9 @@
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
|
||||
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
"version": "7.5.5",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
|
||||
"integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w=="
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.1",
|
||||
@ -3748,11 +4055,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"yauzl": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
|
||||
"integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
|
||||
"requires": {
|
||||
"fd-slicer": "~1.0.1"
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
"request": "^2.88.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axe-core": "^3.3.0",
|
||||
"puppeteer": "^1.20.0"
|
||||
"axe-core": "3.5.3",
|
||||
"puppeteer": "3.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
let
|
||||
sources = import ./nix/sources.nix;
|
||||
nixpkgs = import sources.nixpkgs { };
|
||||
niv = import sources.niv { };
|
||||
system = if builtins.currentSystem == "aarch64-darwin" then "x86_64-darwin" else builtins.currentSystem;
|
||||
nixpkgs = import sources.nixpkgs { inherit system; };
|
||||
niv = nixpkgs.callPackage sources.niv { };
|
||||
in with nixpkgs;
|
||||
stdenv.mkDerivation {
|
||||
name = "noredink-ui";
|
||||
|
74
src/InputErrorInternal.elm
Normal file
74
src/InputErrorInternal.elm
Normal file
@ -0,0 +1,74 @@
|
||||
module InputErrorInternal exposing
|
||||
( ErrorState, init
|
||||
, setErrorIf, setErrorMessage
|
||||
, getIsInError, getErrorMessage
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs ErrorState, init
|
||||
@docs setErrorIf, setErrorMessage
|
||||
@docs getIsInError, getErrorMessage
|
||||
|
||||
-}
|
||||
|
||||
|
||||
{-| -}
|
||||
type ErrorState
|
||||
= NoError
|
||||
| Error { message : Maybe String }
|
||||
|
||||
|
||||
{-| -}
|
||||
init : ErrorState
|
||||
init =
|
||||
NoError
|
||||
|
||||
|
||||
{-| -}
|
||||
setErrorIf : Bool -> { config | error : ErrorState } -> { config | error : ErrorState }
|
||||
setErrorIf isInError_ config =
|
||||
{ config
|
||||
| error =
|
||||
if isInError_ then
|
||||
Error { message = Nothing }
|
||||
|
||||
else
|
||||
NoError
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
setErrorMessage : Maybe String -> { config | error : ErrorState } -> { config | error : ErrorState }
|
||||
setErrorMessage maybeMessage config =
|
||||
{ config
|
||||
| error =
|
||||
case maybeMessage of
|
||||
Nothing ->
|
||||
NoError
|
||||
|
||||
Just message ->
|
||||
Error { message = Just message }
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
getIsInError : ErrorState -> Bool
|
||||
getIsInError error =
|
||||
case error of
|
||||
NoError ->
|
||||
False
|
||||
|
||||
Error _ ->
|
||||
True
|
||||
|
||||
|
||||
{-| -}
|
||||
getErrorMessage : ErrorState -> Maybe String
|
||||
getErrorMessage error =
|
||||
case error of
|
||||
NoError ->
|
||||
Nothing
|
||||
|
||||
Error { message } ->
|
||||
message
|
45
src/InputLabelInternal.elm
Normal file
45
src/InputLabelInternal.elm
Normal file
@ -0,0 +1,45 @@
|
||||
module InputLabelInternal exposing (view)
|
||||
|
||||
{-|
|
||||
|
||||
@docs view
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html exposing (Html)
|
||||
import Accessibility.Styled.Style as Accessibility
|
||||
import Css
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import InputErrorInternal exposing (ErrorState)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.InputStyles.V3 as InputStyles exposing (Theme)
|
||||
|
||||
|
||||
{-| -}
|
||||
view :
|
||||
{ for : String, label : String, theme : Theme }
|
||||
-> { config | error : ErrorState, noMarginTop : Bool, hideLabel : Bool }
|
||||
-> Html msg
|
||||
view { for, label, theme } config =
|
||||
let
|
||||
extraStyles =
|
||||
if config.hideLabel then
|
||||
Accessibility.invisible
|
||||
|
||||
else
|
||||
[]
|
||||
in
|
||||
Html.label
|
||||
([ Attributes.for for
|
||||
, Attributes.css
|
||||
[ InputStyles.label theme (InputErrorInternal.getIsInError config.error)
|
||||
, if config.noMarginTop then
|
||||
Css.top (Css.px -InputStyles.defaultMarginTop)
|
||||
|
||||
else
|
||||
Css.batch []
|
||||
]
|
||||
]
|
||||
++ extraStyles
|
||||
)
|
||||
[ Html.text label ]
|
@ -4,7 +4,7 @@ module Nri.Ui.Button.V10 exposing
|
||||
, icon, custom, css, nriDescription, testId, id
|
||||
, onClick
|
||||
, href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||
, small, medium, large
|
||||
, small, medium, large, modal
|
||||
, exactWidth, boundedWidth, unboundedWidth, fillContainerWidth
|
||||
, primary, secondary, danger, premium
|
||||
, enabled, unfulfilled, disabled, error, loading, success
|
||||
@ -19,6 +19,7 @@ module Nri.Ui.Button.V10 exposing
|
||||
|
||||
- uses ClickableAttributes
|
||||
- adds `nriDescription`, `testId`, and `id` helpers
|
||||
- adds `modal` helper, an alias for `large` size
|
||||
|
||||
|
||||
# Changes from V9:
|
||||
@ -42,7 +43,7 @@ module Nri.Ui.Button.V10 exposing
|
||||
|
||||
## Sizing
|
||||
|
||||
@docs small, medium, large
|
||||
@docs small, medium, large, modal
|
||||
@docs exactWidth, boundedWidth, unboundedWidth, fillContainerWidth
|
||||
|
||||
|
||||
@ -265,6 +266,13 @@ large =
|
||||
set (\attributes -> { attributes | size = Large })
|
||||
|
||||
|
||||
{-| Alias for Button.large
|
||||
-}
|
||||
modal : Attribute msg
|
||||
modal =
|
||||
large
|
||||
|
||||
|
||||
|
||||
-- BUTTON WIDTH
|
||||
|
||||
|
@ -2,7 +2,7 @@ module Nri.Ui.ClickableText.V3 exposing
|
||||
( button
|
||||
, link
|
||||
, Attribute
|
||||
, small, medium, large
|
||||
, small, medium, large, modal
|
||||
, onClick
|
||||
, href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||
, icon
|
||||
@ -19,6 +19,7 @@ module Nri.Ui.ClickableText.V3 exposing
|
||||
- removes underline on hover and recolors to azureDark
|
||||
- removes bottom border
|
||||
- adds `nriDescription`, `testId`, and `id` helpers
|
||||
- adds `modal` helper, for use in modal footers, same as applying large and Css.marginTop (Css.px 15)
|
||||
|
||||
|
||||
# Changes from V2
|
||||
@ -54,7 +55,7 @@ HTML `<a>` elements and are created here with `*Link` functions.
|
||||
|
||||
## Sizing
|
||||
|
||||
@docs small, medium, large
|
||||
@docs small, medium, large, modal
|
||||
|
||||
|
||||
## Behavior
|
||||
@ -101,6 +102,19 @@ large =
|
||||
set (\attributes -> { attributes | size = Large })
|
||||
|
||||
|
||||
{-| For use in Modal footers (adds `large` and `Css.marginTop (Css.px 15)`)
|
||||
-}
|
||||
modal : Attribute msg
|
||||
modal =
|
||||
set
|
||||
(\attributes ->
|
||||
{ attributes
|
||||
| size = Large
|
||||
, customStyles = List.append attributes.customStyles [ Css.marginTop (Css.px 15) ]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
type Size
|
||||
= Small
|
||||
| Medium
|
||||
|
@ -17,7 +17,7 @@ import Html.Styled.Attributes
|
||||
import Nri.Ui
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.MediaQuery.V1 exposing (mobile)
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -197,13 +197,15 @@ interactableWithLabel label content =
|
||||
"label"
|
||||
labelStyles
|
||||
[]
|
||||
[ Text.smallBody []
|
||||
[ div
|
||||
[ Html.Styled.Attributes.css
|
||||
[ margin (px 7)
|
||||
[ Text.smallBody
|
||||
[ Text.html
|
||||
[ div
|
||||
[ Html.Styled.Attributes.css
|
||||
[ margin (px 7)
|
||||
]
|
||||
]
|
||||
[ text label
|
||||
]
|
||||
]
|
||||
[ text label
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -54,7 +54,7 @@ import Nri.Ui
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Html.Attributes.V2 as ExtraAttributes
|
||||
import Nri.Ui.MediaQuery.V1 exposing (mobile)
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
{-| -}
|
||||
|
@ -1,6 +1,6 @@
|
||||
module Nri.Ui.InputStyles.V3 exposing
|
||||
( label, Theme(..), input
|
||||
, inputPaddingVertical, inputLineHeight, textAreaHeight, writingLineHeight, writingPadding, writingPaddingTop, writingMinHeight
|
||||
, inputPaddingVertical, inputLineHeight, textAreaHeight, writingLineHeight, writingPadding, writingPaddingTop, writingMinHeight, defaultMarginTop
|
||||
)
|
||||
|
||||
{-| InputStyles used by the TextInput and TextArea widgets.
|
||||
@ -10,11 +10,13 @@ module Nri.Ui.InputStyles.V3 exposing
|
||||
|
||||
## Shared hardcoded values
|
||||
|
||||
@docs inputPaddingVertical, inputLineHeight, textAreaHeight, writingLineHeight, writingPadding, writingPaddingTop, writingMinHeight
|
||||
@docs inputPaddingVertical, inputLineHeight, textAreaHeight, writingLineHeight, writingPadding, writingPaddingTop, writingMinHeight, defaultMarginTop
|
||||
|
||||
|
||||
## Changelog
|
||||
|
||||
- patch: expose defaultMarginTop
|
||||
|
||||
- V3: add UserGenerated
|
||||
|
||||
-}
|
||||
@ -108,6 +110,12 @@ label theme inError =
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
defaultMarginTop : Float
|
||||
defaultMarginTop =
|
||||
9
|
||||
|
||||
|
||||
{-| In order to use these styles in an input module, you will need to add the class "override-sass-styles". This is because sass styles in the monolith have higher precendence than the class styles here.
|
||||
-}
|
||||
input : Theme -> Bool -> Style
|
||||
@ -127,7 +135,7 @@ input theme isInError =
|
||||
, display inlineBlock
|
||||
, verticalAlign top
|
||||
, marginBottom zero
|
||||
, marginTop (px 9)
|
||||
, marginTop (px defaultMarginTop)
|
||||
, boxShadow6 inset zero (px 3) zero zero gray92
|
||||
, property "transition" "border-color 0.4s ease"
|
||||
, boxSizing borderBox
|
||||
|
@ -23,7 +23,7 @@ import Nri.Ui.Html.V3 exposing (viewIf)
|
||||
|
||||
{-| The default page information is for the button
|
||||
which will direct the user back to the main page of
|
||||
the SPA. Specify it's name and the message which will
|
||||
the SPA. Specify its name and the message which will
|
||||
navigate to the page.
|
||||
-}
|
||||
type alias DefaultPage msg =
|
||||
|
434
src/Nri/Ui/Select/V8.elm
Normal file
434
src/Nri/Ui/Select/V8.elm
Normal file
@ -0,0 +1,434 @@
|
||||
module Nri.Ui.Select.V8 exposing
|
||||
( view, generateId
|
||||
, Choice, choices
|
||||
, value
|
||||
, Attribute, defaultDisplayText
|
||||
, hiddenLabel, visibleLabel
|
||||
, errorIf, errorMessage
|
||||
, custom, nriDescription, id, testId
|
||||
, containerCss, noMargin
|
||||
)
|
||||
|
||||
{-| Build a select input with a label, optional guidance, and error messaging.
|
||||
|
||||
|
||||
# Changes from V7
|
||||
|
||||
- view adds a label
|
||||
- adds standard custom, nriDescription, etc. attributes
|
||||
- switches to a list-based attribute API from a record-based API
|
||||
|
||||
@docs view, generateId
|
||||
|
||||
|
||||
### Input types
|
||||
|
||||
@docs Choice, choices
|
||||
|
||||
|
||||
### Input content
|
||||
|
||||
@docs value
|
||||
|
||||
|
||||
### Attributes
|
||||
|
||||
@docs Attribute, defaultDisplayText
|
||||
@docs hiddenLabel, visibleLabel
|
||||
@docs errorIf, errorMessage
|
||||
@docs custom, nriDescription, id, testId
|
||||
@docs containerCss, noMargin
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html exposing (Html)
|
||||
import Css
|
||||
import Dict
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import Html.Styled.Events as Events
|
||||
import InputErrorInternal exposing (ErrorState)
|
||||
import InputLabelInternal
|
||||
import Json.Decode exposing (Decoder)
|
||||
import Nri.Ui
|
||||
import Nri.Ui.Colors.Extra as ColorsExtra
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.CssVendorPrefix.V1 as VendorPrefixed
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 as Extra
|
||||
import Nri.Ui.Html.V3 exposing (viewJust)
|
||||
import Nri.Ui.InputStyles.V3 as InputStyles
|
||||
import Nri.Ui.Message.V3 as Message
|
||||
import Nri.Ui.Util
|
||||
import SolidColor
|
||||
|
||||
|
||||
{-| -}
|
||||
defaultDisplayText : String -> Attribute value
|
||||
defaultDisplayText text =
|
||||
Attribute (\config -> { config | defaultDisplayText = Just text })
|
||||
|
||||
|
||||
{-| -}
|
||||
value : Maybe value -> Attribute value
|
||||
value value_ =
|
||||
Attribute (\config -> { config | value = value_ })
|
||||
|
||||
|
||||
{-| Sets whether or not the field will be highlighted as having a validation error.
|
||||
|
||||
If you have an error message to display, use `errorMessage` instead.
|
||||
|
||||
-}
|
||||
errorIf : Bool -> Attribute value
|
||||
errorIf =
|
||||
Attribute << InputErrorInternal.setErrorIf
|
||||
|
||||
|
||||
{-| If `Just`, the field will be highlighted as having a validation error,
|
||||
and the given error message will be shown.
|
||||
-}
|
||||
errorMessage : Maybe String -> Attribute value
|
||||
errorMessage =
|
||||
Attribute << InputErrorInternal.setErrorMessage
|
||||
|
||||
|
||||
{-| Hides the visible label. (There will still be an invisible label for screen readers.)
|
||||
-}
|
||||
hiddenLabel : Attribute value
|
||||
hiddenLabel =
|
||||
Attribute (\config -> { config | hideLabel = True })
|
||||
|
||||
|
||||
{-| Default behavior.
|
||||
-}
|
||||
visibleLabel : Attribute value
|
||||
visibleLabel =
|
||||
Attribute (\config -> { config | hideLabel = False })
|
||||
|
||||
|
||||
{-| Set a custom ID for this text input and label. If you don't set this,
|
||||
we'll automatically generate one from the label you pass in, but this can
|
||||
cause problems if you have more than one text input with the same label on
|
||||
the page. Use this to be more specific and avoid issues with duplicate IDs!
|
||||
-}
|
||||
id : String -> Attribute value
|
||||
id id_ =
|
||||
Attribute (\config -> { config | id = Just id_ })
|
||||
|
||||
|
||||
{-| Use this helper to add custom attributes.
|
||||
|
||||
Do NOT use this helper to add css styles, as they may not be applied the way
|
||||
you want/expect if underlying styles change.
|
||||
Instead, please use the `css` helper.
|
||||
|
||||
-}
|
||||
custom : List (Html.Attribute Never) -> Attribute value
|
||||
custom attributes =
|
||||
Attribute (\config -> { config | custom = config.custom ++ attributes })
|
||||
|
||||
|
||||
{-| -}
|
||||
nriDescription : String -> Attribute value
|
||||
nriDescription description =
|
||||
custom [ Extra.nriDescription description ]
|
||||
|
||||
|
||||
{-| -}
|
||||
testId : String -> Attribute value
|
||||
testId id_ =
|
||||
custom [ Extra.testId id_ ]
|
||||
|
||||
|
||||
{-| Adds CSS to the element containing the input.
|
||||
-}
|
||||
containerCss : List Css.Style -> Attribute value
|
||||
containerCss styles =
|
||||
Attribute <|
|
||||
\config -> { config | containerCss = config.containerCss ++ styles }
|
||||
|
||||
|
||||
{-| Remove default spacing from the Input.
|
||||
-}
|
||||
noMargin : Bool -> Attribute value
|
||||
noMargin removeMargin =
|
||||
Attribute <| \config -> { config | noMarginTop = removeMargin }
|
||||
|
||||
|
||||
{-| A single possible choice.
|
||||
-}
|
||||
type alias Choice value =
|
||||
{ label : String, value : value }
|
||||
|
||||
|
||||
{-| -}
|
||||
choices : (value -> String) -> List (Choice value) -> Attribute value
|
||||
choices valueToString choices_ =
|
||||
Attribute
|
||||
(\config ->
|
||||
{ config
|
||||
| valueToString = Just valueToString
|
||||
, choices = choices_
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| Customizations for the Select.
|
||||
-}
|
||||
type Attribute value
|
||||
= Attribute (Config value -> Config value)
|
||||
|
||||
|
||||
applyConfig : List (Attribute value) -> Config value
|
||||
applyConfig attributes =
|
||||
List.foldl (\(Attribute update) config -> update config)
|
||||
defaultConfig
|
||||
attributes
|
||||
|
||||
|
||||
type alias Config value =
|
||||
{ id : Maybe String
|
||||
, value : Maybe value
|
||||
, choices : List (Choice value)
|
||||
, valueToString : Maybe (value -> String)
|
||||
, defaultDisplayText : Maybe String
|
||||
, error : ErrorState
|
||||
, hideLabel : Bool
|
||||
, noMarginTop : Bool
|
||||
, containerCss : List Css.Style
|
||||
, custom : List (Html.Attribute Never)
|
||||
}
|
||||
|
||||
|
||||
defaultConfig : Config value
|
||||
defaultConfig =
|
||||
{ id = Nothing
|
||||
, value = Nothing
|
||||
, choices = []
|
||||
, valueToString = Nothing
|
||||
, defaultDisplayText = Nothing
|
||||
, error = InputErrorInternal.init
|
||||
, hideLabel = False
|
||||
, noMarginTop = False
|
||||
, containerCss = []
|
||||
, custom = []
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
view : String -> List (Attribute a) -> Html a
|
||||
view label attributes =
|
||||
let
|
||||
config =
|
||||
applyConfig attributes
|
||||
|
||||
isInError_ =
|
||||
InputErrorInternal.getIsInError config.error
|
||||
|
||||
id_ =
|
||||
Maybe.withDefault (generateId label) config.id
|
||||
in
|
||||
Html.div
|
||||
[ css
|
||||
([ Css.position Css.relative
|
||||
, if config.noMarginTop then
|
||||
Css.batch []
|
||||
|
||||
else
|
||||
Css.paddingTop (Css.px InputStyles.defaultMarginTop)
|
||||
]
|
||||
++ config.containerCss
|
||||
)
|
||||
]
|
||||
[ InputLabelInternal.view
|
||||
{ for = id_
|
||||
, label = label
|
||||
, theme = InputStyles.Standard
|
||||
}
|
||||
config
|
||||
, viewSelect
|
||||
{ choices = config.choices
|
||||
, current = config.value
|
||||
, id = id_
|
||||
, custom = config.custom
|
||||
, valueToString = config.valueToString
|
||||
, defaultDisplayText = config.defaultDisplayText
|
||||
, isInError = isInError_
|
||||
}
|
||||
, viewJust
|
||||
(\m ->
|
||||
Message.view
|
||||
[ Message.tiny
|
||||
, Message.error
|
||||
, Message.plaintext m
|
||||
, Message.alertRole
|
||||
]
|
||||
)
|
||||
(InputErrorInternal.getErrorMessage config.error)
|
||||
]
|
||||
|
||||
|
||||
viewSelect :
|
||||
{ choices : List (Choice a)
|
||||
, current : Maybe a
|
||||
, id : String
|
||||
, valueToString : Maybe (a -> String)
|
||||
, defaultDisplayText : Maybe String
|
||||
, isInError : Bool
|
||||
, custom : List (Html.Attribute Never)
|
||||
}
|
||||
-> Html a
|
||||
viewSelect config =
|
||||
let
|
||||
stringChoices =
|
||||
case config.valueToString of
|
||||
Just valueToString ->
|
||||
List.map
|
||||
(\choice ->
|
||||
{ label = choice.label
|
||||
, idAndValue = generateId (valueToString choice.value)
|
||||
, value = choice.value
|
||||
}
|
||||
)
|
||||
config.choices
|
||||
|
||||
Nothing ->
|
||||
[]
|
||||
|
||||
valueLookup =
|
||||
stringChoices
|
||||
|> List.map (\x -> ( x.idAndValue, x.value ))
|
||||
|> Dict.fromList
|
||||
|
||||
decodeValue string =
|
||||
Dict.get string valueLookup
|
||||
|> Maybe.map Json.Decode.succeed
|
||||
|> Maybe.withDefault
|
||||
-- At present, elm/virtual-dom throws this failure away.
|
||||
(Json.Decode.fail
|
||||
("Nri.Select: could not decode the value: "
|
||||
++ string
|
||||
++ "\nexpected one of: "
|
||||
++ String.join ", " (Dict.keys valueLookup)
|
||||
)
|
||||
)
|
||||
|
||||
onSelectHandler =
|
||||
Events.on "change" (Events.targetValue |> Json.Decode.andThen decodeValue)
|
||||
|
||||
defaultOption =
|
||||
config.defaultDisplayText
|
||||
|> Maybe.map (viewDefaultChoice config.current >> List.singleton)
|
||||
|> Maybe.withDefault []
|
||||
|
||||
currentVal =
|
||||
if config.current == Nothing && config.defaultDisplayText == Nothing then
|
||||
config.choices
|
||||
|> List.head
|
||||
|> Maybe.map .value
|
||||
|
||||
else
|
||||
config.current
|
||||
in
|
||||
stringChoices
|
||||
|> List.map (viewChoice currentVal)
|
||||
|> (++) defaultOption
|
||||
|> Nri.Ui.styled Html.select
|
||||
"nri-select-menu"
|
||||
[ -- border
|
||||
Css.border3 (Css.px 1)
|
||||
Css.solid
|
||||
(if config.isInError then
|
||||
Colors.purple
|
||||
|
||||
else
|
||||
Colors.gray75
|
||||
)
|
||||
, Css.borderBottomWidth (Css.px 3)
|
||||
, Css.borderRadius (Css.px 8)
|
||||
, Css.focus [ Css.borderColor Colors.azure ]
|
||||
|
||||
-- Font and color
|
||||
, Css.color Colors.gray20
|
||||
, Fonts.baseFont
|
||||
, Css.fontSize (Css.px 15)
|
||||
, Css.fontWeight (Css.int 600)
|
||||
, Css.textOverflow Css.ellipsis
|
||||
, Css.overflow Css.hidden
|
||||
, Css.whiteSpace Css.noWrap
|
||||
|
||||
-- Interaction
|
||||
, Css.cursor Css.pointer
|
||||
|
||||
-- Size and spacing
|
||||
, Css.height (Css.px 45)
|
||||
, Css.width (Css.pct 100)
|
||||
, Css.paddingLeft (Css.px 15)
|
||||
, Css.paddingRight (Css.px 30)
|
||||
|
||||
-- Icons
|
||||
, selectArrowsCss
|
||||
]
|
||||
(onSelectHandler
|
||||
:: Attributes.id config.id
|
||||
:: List.map (Attributes.map never) config.custom
|
||||
)
|
||||
|
||||
|
||||
viewDefaultChoice : Maybe a -> String -> Html a
|
||||
viewDefaultChoice current displayText =
|
||||
Html.option
|
||||
[ Attributes.selected (current == Nothing)
|
||||
, Attributes.disabled True
|
||||
]
|
||||
[ Html.text displayText ]
|
||||
|
||||
|
||||
viewChoice : Maybe a -> { value : a, idAndValue : String, label : String } -> Html a
|
||||
viewChoice current choice =
|
||||
let
|
||||
isSelected =
|
||||
current
|
||||
|> Maybe.map ((==) choice.value)
|
||||
|> Maybe.withDefault False
|
||||
in
|
||||
Html.option
|
||||
[ Attributes.id choice.idAndValue
|
||||
, Attributes.value choice.idAndValue
|
||||
, Attributes.selected isSelected
|
||||
]
|
||||
[ Html.text choice.label ]
|
||||
|
||||
|
||||
{-| Pass in the label to generate the default DOM element id used by a `Select.view` with the given label.
|
||||
-}
|
||||
generateId : String -> String
|
||||
generateId x =
|
||||
"nri-select-" ++ Nri.Ui.Util.dashify (Nri.Ui.Util.removePunctuation x)
|
||||
|
||||
|
||||
selectArrowsCss : Css.Style
|
||||
selectArrowsCss =
|
||||
let
|
||||
color =
|
||||
SolidColor.toRGBString (ColorsExtra.fromCssColor Colors.azure)
|
||||
in
|
||||
Css.batch
|
||||
[ """<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12px" height="16px" viewBox="0 0 12 16"><g fill=" """
|
||||
++ color
|
||||
++ """ "><path d="M2.10847,9.341803 C1.65347,8.886103 0.91427,8.886103 0.45857,9.341803 C0.23107,9.570003 0.11697,9.868203 0.11697,10.167103 C0.11697,10.465303 0.23107,10.763503 0.45857,10.991703 L5.12547,15.657903 C5.57977,16.114303 6.31897,16.114303 6.77537,15.657903 L11.44157,10.991703 C11.89727,10.536003 11.89727,9.797503 11.44157,9.341803 C10.98657,8.886103 10.24667,8.886103 9.79167,9.341803 L5.95007,13.182703 L2.10847,9.341803 Z"/><path d="M1.991556,6.658179 C1.536659,7.11394 0.797279,7.11394 0.3416911,6.658179 C0.1140698,6.43004 0,6.13173 0,5.83325 C0,5.53476 0.1140698,5.23645 0.3416911,5.00831 L5.008185,0.34182 C5.463081,-0.11394 6.202461,-0.11394 6.65805,0.34182 L11.32454,5.00831 C11.78031,5.4639 11.78031,6.202592 11.32454,6.658179 C10.86965,7.11394 10.13027,7.11394 9.674679,6.658179 L5.833118,2.81679 L1.991556,6.658179 Z"/></g></svg> """
|
||||
|> urlUtf8
|
||||
|> Css.property "background"
|
||||
, Css.backgroundColor Colors.white
|
||||
|
||||
-- "appearance: none" removes the default dropdown arrows
|
||||
, VendorPrefixed.property "appearance" "none"
|
||||
, Css.backgroundRepeat Css.noRepeat
|
||||
, Css.property "background-position" "center right -20px"
|
||||
, Css.backgroundOrigin Css.contentBox
|
||||
]
|
||||
|
||||
|
||||
urlUtf8 : String -> String
|
||||
urlUtf8 content =
|
||||
"""url('data:image/svg+xml;utf8,""" ++ content ++ """')"""
|
@ -1,8 +1,8 @@
|
||||
module Nri.Ui.Switch.V1 exposing (view, Attribute, onSwitch, disabled, id, label)
|
||||
module Nri.Ui.Switch.V1 exposing (view, Attribute, onSwitch, disabled, id, label, custom)
|
||||
|
||||
{-|
|
||||
|
||||
@docs view, Attribute, onSwitch, disabled, id, label
|
||||
@docs view, Attribute, onSwitch, disabled, id, label, custom
|
||||
|
||||
-}
|
||||
|
||||
@ -27,6 +27,7 @@ type Attribute msg
|
||||
| Id String
|
||||
| Label (Html msg)
|
||||
| Disabled
|
||||
| Custom (List (Html.Attribute Never))
|
||||
|
||||
|
||||
{-| Specify what happens when the switch is toggled.
|
||||
@ -63,10 +64,18 @@ label =
|
||||
Label
|
||||
|
||||
|
||||
{-| Pass custom attributes through to be attached to the underlying input.
|
||||
-}
|
||||
custom : List (Html.Attribute Never) -> Attribute msg
|
||||
custom =
|
||||
Custom
|
||||
|
||||
|
||||
type alias Config msg =
|
||||
{ onSwitch : Maybe (Bool -> msg)
|
||||
, id : String
|
||||
, label : Maybe (Html msg)
|
||||
, attributes : List (Html.Attribute Never)
|
||||
}
|
||||
|
||||
|
||||
@ -75,6 +84,7 @@ defaultConfig =
|
||||
{ onSwitch = Nothing
|
||||
, id = "nri-ui-switch-with-default-id"
|
||||
, label = Nothing
|
||||
, attributes = []
|
||||
}
|
||||
|
||||
|
||||
@ -93,6 +103,9 @@ customize attr config =
|
||||
Label label_ ->
|
||||
{ config | label = Just label_ }
|
||||
|
||||
Custom custom_ ->
|
||||
{ config | attributes = custom_ }
|
||||
|
||||
|
||||
{-| Render a switch. The boolean here indicates whether the switch is on
|
||||
or not.
|
||||
@ -133,6 +146,7 @@ view attrs isOn =
|
||||
{ id = config.id
|
||||
, onCheck = config.onSwitch
|
||||
, checked = isOn
|
||||
, attributes = config.attributes
|
||||
}
|
||||
, Nri.Ui.Svg.V1.toHtml
|
||||
(viewSwitch
|
||||
@ -162,26 +176,29 @@ viewCheckbox :
|
||||
{ id : String
|
||||
, onCheck : Maybe (Bool -> msg)
|
||||
, checked : Bool
|
||||
, attributes : List (Html.Attribute Never)
|
||||
}
|
||||
-> Html msg
|
||||
viewCheckbox config =
|
||||
Html.checkbox config.id
|
||||
(Just config.checked)
|
||||
[ Attributes.id config.id
|
||||
, Attributes.css
|
||||
([ Attributes.id config.id
|
||||
, Attributes.css
|
||||
[ Css.position Css.absolute
|
||||
, Css.top (Css.px 10)
|
||||
, Css.left (Css.px 10)
|
||||
, Css.zIndex (Css.int 0)
|
||||
, Css.opacity (Css.num 0)
|
||||
]
|
||||
, case config.onCheck of
|
||||
, case config.onCheck of
|
||||
Just onCheck ->
|
||||
Events.onCheck onCheck
|
||||
|
||||
Nothing ->
|
||||
Widget.disabled True
|
||||
]
|
||||
]
|
||||
++ List.map (Attributes.map never) config.attributes
|
||||
)
|
||||
|
||||
|
||||
viewSwitch :
|
||||
|
346
src/Nri/Ui/Text/V6.elm
Normal file
346
src/Nri/Ui/Text/V6.elm
Normal file
@ -0,0 +1,346 @@
|
||||
module Nri.Ui.Text.V6 exposing
|
||||
( caption, mediumBody, mediumBodyGray, smallBody, smallBodyGray
|
||||
, ugMediumBody, ugSmallBody
|
||||
, plaintext, markdown, html
|
||||
, Attribute, noBreak, css, id, custom
|
||||
, nriDescription, testId
|
||||
)
|
||||
|
||||
{-| Changes from V5:
|
||||
|
||||
- adds helpers: `custom`, `nriDescription`,`testId`,`id`
|
||||
- instead of view helpers that take HTML, offer attribute helpers supporting plaintext, markdown, and html content
|
||||
- :skull: remove noWidow, which is not used
|
||||
- noBreak now takes a bool
|
||||
|
||||
|
||||
## Understanding spacing
|
||||
|
||||
- All text styles have a specific line-height. This is set so that when text in the given style
|
||||
is long enough to wrap, the spacing between wrapped lines looks good.
|
||||
- No text styles have padding.
|
||||
- **Paragraph styles** only have bottom margin, but with **:last-child bottom margin set to zero**.
|
||||
This bottom margin is set to look good when multiple paragraphs of the same style follow one another.
|
||||
- If you want content after the paragraph and don't want the margin, put the paragraph in a `div` so that it will be the last-child, which will get rid of the bottom margin.
|
||||
- **User-authored content blocks** preserve line breaks and do not have margin.
|
||||
|
||||
|
||||
## Headings
|
||||
|
||||
You're in the wrong place! Headings live in Nri.Ui.Heading.V2.
|
||||
|
||||
|
||||
## Paragraph styles
|
||||
|
||||
@docs caption, mediumBody, mediumBodyGray, smallBody, smallBodyGray
|
||||
|
||||
|
||||
## User-authored content blocks:
|
||||
|
||||
@docs ugMediumBody, ugSmallBody
|
||||
|
||||
|
||||
# Content
|
||||
|
||||
@docs plaintext, markdown, html
|
||||
|
||||
|
||||
## Customizations
|
||||
|
||||
@docs Attribute, noBreak, css, id, custom
|
||||
@docs nriDescription, testId
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html exposing (..)
|
||||
import Css exposing (..)
|
||||
import Css.Global exposing (a, descendants)
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Markdown
|
||||
import Nri.Ui.Colors.V1 exposing (..)
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 as ExtraAttributes
|
||||
|
||||
|
||||
{-| -}
|
||||
type Attribute msg
|
||||
= Attribute (Settings msg -> Settings msg)
|
||||
|
||||
|
||||
type alias Settings msg =
|
||||
{ noBreak : Bool
|
||||
, styles : List Css.Style
|
||||
, customAttributes : List (Html.Attribute Never)
|
||||
, content : List (Html msg)
|
||||
}
|
||||
|
||||
|
||||
defaultSettings : Settings msg
|
||||
defaultSettings =
|
||||
{ noBreak = False
|
||||
, styles = []
|
||||
, customAttributes = []
|
||||
, content = []
|
||||
}
|
||||
|
||||
|
||||
buildSettings : List (Attribute msg) -> Settings msg
|
||||
buildSettings =
|
||||
List.foldl (\(Attribute f) acc -> f acc) defaultSettings
|
||||
|
||||
|
||||
{-| Pass True to prevent text from ever wrapping.
|
||||
|
||||
The default Text behavior is `noBreak False`, which means content will wrap.
|
||||
|
||||
-}
|
||||
noBreak : Bool -> Attribute msg
|
||||
noBreak noBreak_ =
|
||||
Attribute (\config -> { config | noBreak = noBreak_ })
|
||||
|
||||
|
||||
{-| Use this helper to add custom attributes.
|
||||
|
||||
Do NOT use this helper to add css styles, as they may not be applied the way
|
||||
you want/expect if underlying styles change.
|
||||
Instead, please use the `css` helper.
|
||||
|
||||
-}
|
||||
custom : List (Html.Attribute Never) -> Attribute msg
|
||||
custom attributes =
|
||||
Attribute <|
|
||||
\config ->
|
||||
{ config
|
||||
| customAttributes = List.append config.customAttributes attributes
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
nriDescription : String -> Attribute msg
|
||||
nriDescription description =
|
||||
custom [ ExtraAttributes.nriDescription description ]
|
||||
|
||||
|
||||
{-| -}
|
||||
testId : String -> Attribute msg
|
||||
testId id_ =
|
||||
custom [ ExtraAttributes.testId id_ ]
|
||||
|
||||
|
||||
{-| -}
|
||||
id : String -> Attribute msg
|
||||
id id_ =
|
||||
custom [ Attributes.id id_ ]
|
||||
|
||||
|
||||
{-| Add some custom CSS to the text. If you find yourself using this a lot,
|
||||
please add a stricter attribute to noredink-ui!
|
||||
-}
|
||||
css : List Style -> Attribute msg
|
||||
css styles =
|
||||
Attribute (\config -> { config | styles = config.styles ++ styles })
|
||||
|
||||
|
||||
{-| -}
|
||||
view : List (Attribute msg) -> Html msg
|
||||
view attributes =
|
||||
let
|
||||
settings : Settings msg
|
||||
settings =
|
||||
buildSettings attributes
|
||||
in
|
||||
p
|
||||
(Attributes.css
|
||||
[ if settings.noBreak then
|
||||
whiteSpace noWrap
|
||||
|
||||
else
|
||||
batch []
|
||||
, batch settings.styles
|
||||
]
|
||||
:: settings.customAttributes
|
||||
)
|
||||
settings.content
|
||||
|
||||
|
||||
{-| This is some medium body copy.
|
||||
-}
|
||||
mediumBody : List (Attribute msg) -> Html msg
|
||||
mediumBody attributes =
|
||||
view
|
||||
(css
|
||||
(paragraphStyles
|
||||
{ font = Fonts.baseFont
|
||||
, color = gray20
|
||||
, size = 18
|
||||
, lineHeight = 28
|
||||
, weight = 400
|
||||
, margin = 10
|
||||
}
|
||||
)
|
||||
:: attributes
|
||||
)
|
||||
|
||||
|
||||
{-| `mediumBody`, but with a lighter gray color than the default.
|
||||
-}
|
||||
mediumBodyGray : List (Attribute msg) -> Html msg
|
||||
mediumBodyGray attributes =
|
||||
mediumBody (css [ Css.color gray45 ] :: attributes)
|
||||
|
||||
|
||||
{-| This is some small body copy.
|
||||
-}
|
||||
smallBody : List (Attribute msg) -> Html msg
|
||||
smallBody attributes =
|
||||
view
|
||||
(css
|
||||
(paragraphStyles
|
||||
{ font = Fonts.baseFont
|
||||
, color = gray20
|
||||
, size = 15
|
||||
, lineHeight = 23
|
||||
, weight = 400
|
||||
, margin = 7
|
||||
}
|
||||
)
|
||||
:: attributes
|
||||
)
|
||||
|
||||
|
||||
{-| This is some small body copy but it's gray.
|
||||
-}
|
||||
smallBodyGray : List (Attribute msg) -> Html msg
|
||||
smallBodyGray attributes =
|
||||
view
|
||||
(css
|
||||
(paragraphStyles
|
||||
{ font = Fonts.baseFont
|
||||
, color = gray45
|
||||
, size = 15
|
||||
, lineHeight = 23
|
||||
, weight = 400
|
||||
, margin = 7
|
||||
}
|
||||
)
|
||||
:: attributes
|
||||
)
|
||||
|
||||
|
||||
paragraphStyles :
|
||||
{ color : Color
|
||||
, font : Style
|
||||
, lineHeight : Float
|
||||
, margin : Float
|
||||
, size : Float
|
||||
, weight : Int
|
||||
}
|
||||
-> List Css.Style
|
||||
paragraphStyles config =
|
||||
[ config.font
|
||||
, fontSize (px config.size)
|
||||
, color config.color
|
||||
, lineHeight (px config.lineHeight)
|
||||
, fontWeight (int config.weight)
|
||||
, padding zero
|
||||
, textAlign left
|
||||
, margin4 (px 0) (px 0) (px config.margin) (px 0)
|
||||
, Css.Global.descendants
|
||||
[ Css.Global.a
|
||||
[ textDecoration none
|
||||
, color azure
|
||||
, borderBottom3 (px 1) solid azure
|
||||
, visited
|
||||
[ color azure ]
|
||||
]
|
||||
]
|
||||
, lastChild
|
||||
[ margin zero
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
{-| This is a little note or caption.
|
||||
-}
|
||||
caption : List (Attribute msg) -> Html msg
|
||||
caption attributes =
|
||||
view
|
||||
(css
|
||||
(paragraphStyles
|
||||
{ font = Fonts.baseFont
|
||||
, color = gray45
|
||||
, size = 13
|
||||
, lineHeight = 18
|
||||
, weight = 400
|
||||
, margin = 5
|
||||
}
|
||||
)
|
||||
:: attributes
|
||||
)
|
||||
|
||||
|
||||
{-| User-generated text.
|
||||
-}
|
||||
ugMediumBody : List (Attribute msg) -> Html msg
|
||||
ugMediumBody attributes =
|
||||
view
|
||||
(css
|
||||
(whiteSpace preLine
|
||||
:: paragraphStyles
|
||||
{ font = Fonts.quizFont
|
||||
, color = gray20
|
||||
, size = 18
|
||||
, lineHeight = 30
|
||||
, weight = 400
|
||||
, margin = 0
|
||||
}
|
||||
)
|
||||
:: attributes
|
||||
)
|
||||
|
||||
|
||||
{-| User-generated text.
|
||||
-}
|
||||
ugSmallBody : List (Attribute msg) -> Html msg
|
||||
ugSmallBody attributes =
|
||||
view
|
||||
(css
|
||||
(whiteSpace preLine
|
||||
:: paragraphStyles
|
||||
{ font = Fonts.quizFont
|
||||
, color = gray20
|
||||
, size = 16
|
||||
, lineHeight = 25
|
||||
, weight = 400
|
||||
, margin = 0
|
||||
}
|
||||
)
|
||||
:: attributes
|
||||
)
|
||||
|
||||
|
||||
{-| Provide a plain-text string.
|
||||
-}
|
||||
plaintext : String -> Attribute msg
|
||||
plaintext content =
|
||||
Attribute <| \config -> { config | content = [ text content ] }
|
||||
|
||||
|
||||
{-| Provide a string that will be rendered as markdown.
|
||||
-}
|
||||
markdown : String -> Attribute msg
|
||||
markdown content =
|
||||
Attribute <|
|
||||
\config ->
|
||||
{ config
|
||||
| content =
|
||||
Markdown.toHtml Nothing content
|
||||
|> List.map fromUnstyled
|
||||
}
|
||||
|
||||
|
||||
{-| Provide a list of custom HTML.
|
||||
-}
|
||||
html : List (Html msg) -> Attribute msg
|
||||
html content =
|
||||
Attribute <| \config -> { config | content = content }
|
801
src/Nri/Ui/TextInput/V7.elm
Normal file
801
src/Nri/Ui/TextInput/V7.elm
Normal file
@ -0,0 +1,801 @@
|
||||
module Nri.Ui.TextInput.V7 exposing
|
||||
( view, generateId
|
||||
, number, float, text, newPassword, currentPassword, email, search
|
||||
, value, map
|
||||
, onFocus, onBlur, onEnter
|
||||
, Attribute, placeholder, autofocus
|
||||
, hiddenLabel, visibleLabel
|
||||
, css, custom, nriDescription, id, testId, noMargin
|
||||
, disabled, loading, errorIf, errorMessage, guidance
|
||||
, writing
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
|
||||
# Changes from V6
|
||||
|
||||
- custom takes a list of attributes and appends them to the end of the previous attributes, instead of prepending a single attr.
|
||||
- change `view` API so it only takes a list of attributes (meaning the value and input type are now passed in as attributes)
|
||||
- make the search icon and reset pattern the default for `search`
|
||||
- add "Show password" and "Hide password" as default behavior for `password` inputs
|
||||
- split password into `newPassword` and `currentPassword` to fix the autocomplete behavior
|
||||
|
||||
@docs view, generateId
|
||||
|
||||
|
||||
### Input types
|
||||
|
||||
@docs number, float, text, newPassword, currentPassword, email, search
|
||||
|
||||
|
||||
### Input content
|
||||
|
||||
@docs value, map
|
||||
|
||||
|
||||
### Event handlers
|
||||
|
||||
@docs onFocus, onBlur, onEnter
|
||||
|
||||
|
||||
### Attributes
|
||||
|
||||
@docs Attribute, placeholder, autofocus
|
||||
@docs hiddenLabel, visibleLabel
|
||||
@docs css, custom, nriDescription, id, testId, noMargin
|
||||
@docs disabled, loading, errorIf, errorMessage, guidance
|
||||
@docs writing
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled.Aria as Aria
|
||||
import Accessibility.Styled.Style as Accessibility
|
||||
import Css exposing (center, num, position, px, relative, textAlign)
|
||||
import Css.Global
|
||||
import Html.Styled as Html exposing (..)
|
||||
import Html.Styled.Attributes as Attributes exposing (..)
|
||||
import Html.Styled.Events as Events
|
||||
import InputErrorInternal exposing (ErrorState)
|
||||
import InputLabelInternal
|
||||
import Keyboard.Event exposing (KeyboardEvent)
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Html.Attributes.V2 as Extra
|
||||
import Nri.Ui.Html.V3 exposing (viewJust)
|
||||
import Nri.Ui.InputStyles.V3 as InputStyles exposing (defaultMarginTop)
|
||||
import Nri.Ui.Message.V3 as Message
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Nri.Ui.Util exposing (dashify)
|
||||
|
||||
|
||||
{-| An input that allows text entry
|
||||
-}
|
||||
text : (String -> msg) -> Attribute String msg
|
||||
text onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Nothing
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows integer entry
|
||||
-}
|
||||
number : (Maybe Int -> msg) -> Attribute (Maybe Int) msg
|
||||
number onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just (Maybe.map String.fromInt >> Maybe.withDefault "")
|
||||
, fromString = Just String.toInt
|
||||
, onInput = Just (String.toInt >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "number"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Nothing
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows float entry
|
||||
-}
|
||||
float : (Maybe Float -> msg) -> Attribute (Maybe Float) msg
|
||||
float onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just (Maybe.map String.fromFloat >> Maybe.withDefault "")
|
||||
, fromString = Just String.toFloat
|
||||
, onInput = Just (String.toFloat >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "number"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Nothing
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows password entry with autocomplete value "new-password"
|
||||
|
||||
If the user types at least one character into the input box, a
|
||||
floating control "Show password" will appear. When clicked, the
|
||||
input type will change from "password" to "text", in order
|
||||
to enable the user to check what they've typed.
|
||||
|
||||
-}
|
||||
newPassword :
|
||||
{ onInput : String -> msg
|
||||
, showPassword : Bool
|
||||
, setShowPassword : Bool -> msg
|
||||
}
|
||||
-> Attribute String msg
|
||||
newPassword =
|
||||
password "new-password"
|
||||
|
||||
|
||||
{-| An input that allows password entry with autocomplete value "current-password"
|
||||
|
||||
If the user types at least one character into the input box, a
|
||||
floating control "Show password" will appear. When clicked, the
|
||||
input type will change from "password" to "text", in order
|
||||
to enable the user to check what they've typed.
|
||||
|
||||
-}
|
||||
currentPassword :
|
||||
{ onInput : String -> msg
|
||||
, showPassword : Bool
|
||||
, setShowPassword : Bool -> msg
|
||||
}
|
||||
-> Attribute String msg
|
||||
currentPassword =
|
||||
password "current-password"
|
||||
|
||||
|
||||
password :
|
||||
String
|
||||
->
|
||||
{ onInput : String -> msg
|
||||
, showPassword : Bool
|
||||
, setShowPassword : Bool -> msg
|
||||
}
|
||||
-> Attribute String msg
|
||||
password autocomplete settings =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just settings.onInput
|
||||
, floatingContent =
|
||||
Just <|
|
||||
viewPasswordFloatingContent
|
||||
(if settings.showPassword then
|
||||
"Hide password"
|
||||
|
||||
else
|
||||
"Show password"
|
||||
)
|
||||
(settings.setShowPassword (not settings.showPassword))
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType =
|
||||
Just <|
|
||||
if settings.showPassword then
|
||||
"text"
|
||||
|
||||
else
|
||||
"password"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just autocomplete
|
||||
, inputCss = Css.paddingRight (Css.px 135) :: config.inputCss
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that is optimized for email entry
|
||||
|
||||
NOTE: this uses `inputmode="email"` so that mobile devices will use the email keyboard,
|
||||
but not `type="email"` because that would enable browser-provided validation which is inconsistent and at odds
|
||||
with our validation UI.
|
||||
|
||||
-}
|
||||
email : (String -> msg) -> Attribute String msg
|
||||
email onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just onInput_
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Just "email"
|
||||
, autocomplete = Just "email"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input with ["search" type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/search) specified.
|
||||
-}
|
||||
search : (String -> msg) -> Attribute String msg
|
||||
search onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, floatingContent = Just viewSearchFloatingContent
|
||||
, onInput = Just onInput_
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "search"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Nothing
|
||||
, inputCss = Css.paddingRight (Css.px 30) :: config.inputCss
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
value : value -> Attribute value msg
|
||||
value value_ =
|
||||
Attribute { emptyEventsAndValues | currentValue = Just value_ } identity
|
||||
|
||||
|
||||
{-| If not explicit placeholder is given, the input label will be used as the placeholder.
|
||||
-}
|
||||
placeholder : String -> Attribute value msg
|
||||
placeholder text_ =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | placeholder = Just text_ }
|
||||
|
||||
|
||||
{-| This disables the input
|
||||
-}
|
||||
disabled : Attribute value msg
|
||||
disabled =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | disabled = True }
|
||||
|
||||
|
||||
{-| Use this while the form the input is a part of is being submitted.
|
||||
-}
|
||||
loading : Attribute value msg
|
||||
loading =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | loading = True }
|
||||
|
||||
|
||||
{-| Sets whether or not the field will be highlighted as having a validation error.
|
||||
-}
|
||||
errorIf : Bool -> Attribute value msg
|
||||
errorIf =
|
||||
Attribute emptyEventsAndValues << InputErrorInternal.setErrorIf
|
||||
|
||||
|
||||
{-| If `Just`, the field will be highlighted as having a validation error,
|
||||
and the given error message will be shown.
|
||||
-}
|
||||
errorMessage : Maybe String -> Attribute value msg
|
||||
errorMessage =
|
||||
Attribute emptyEventsAndValues << InputErrorInternal.setErrorMessage
|
||||
|
||||
|
||||
{-| A guidance message shows below the input, unless an error message is showing instead.
|
||||
-}
|
||||
guidance : String -> Attribute value msg
|
||||
guidance message =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | guidance = Just message }
|
||||
|
||||
|
||||
{-| Hides the visible label. (There will still be an invisible label for screen readers.)
|
||||
-}
|
||||
hiddenLabel : Attribute value msg
|
||||
hiddenLabel =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | hideLabel = True }
|
||||
|
||||
|
||||
{-| Default behavior.
|
||||
-}
|
||||
visibleLabel : Attribute value msg
|
||||
visibleLabel =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | hideLabel = False }
|
||||
|
||||
|
||||
{-| Causes the TextInput to produce the given `msg` when the field is focused.
|
||||
-}
|
||||
onFocus : msg -> Attribute value msg
|
||||
onFocus msg =
|
||||
Attribute { emptyEventsAndValues | onFocus = Just msg } identity
|
||||
|
||||
|
||||
{-| Causes the TextInput to produce the given `msg` when the field is blurred.
|
||||
-}
|
||||
onBlur : msg -> Attribute value msg
|
||||
onBlur msg =
|
||||
Attribute { emptyEventsAndValues | onBlur = Just msg } identity
|
||||
|
||||
|
||||
{-| -}
|
||||
onEnter : msg -> Attribute value msg
|
||||
onEnter msg =
|
||||
Attribute { emptyEventsAndValues | onEnter = Just msg } identity
|
||||
|
||||
|
||||
{-| Sets the `autofocus` attribute of the resulting HTML input.
|
||||
-}
|
||||
autofocus : Attribute value msg
|
||||
autofocus =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | autofocus = True }
|
||||
|
||||
|
||||
{-| Adds CSS to the element containing the input.
|
||||
|
||||
If you want to customize colors, borders, font sizes, etc, you should instead add to the TextInput API
|
||||
to support what you need.
|
||||
|
||||
-}
|
||||
css : List Css.Style -> Attribute value msg
|
||||
css styles =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | containerCss = config.containerCss ++ styles }
|
||||
|
||||
|
||||
{-| Remove default spacing from the Input.
|
||||
-}
|
||||
noMargin : Bool -> Attribute value msg
|
||||
noMargin removeMargin =
|
||||
Attribute emptyEventsAndValues <| \config -> { config | noMarginTop = removeMargin }
|
||||
|
||||
|
||||
{-| Use this helper to add custom attributes.
|
||||
|
||||
Do NOT use this helper to add css styles, as they may not be applied the way
|
||||
you want/expect if underlying styles change.
|
||||
Instead, please use the `css` helper.
|
||||
|
||||
-}
|
||||
custom : List (Html.Attribute Never) -> Attribute value msg
|
||||
custom attributes =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | custom = config.custom ++ attributes }
|
||||
|
||||
|
||||
{-| Set a custom ID for this text input and label. If you don't set this,
|
||||
we'll automatically generate one from the label you pass in, but this can
|
||||
cause problems if you have more than one text input with the same label on
|
||||
the page. Use this to be more specific and avoid issues with duplicate IDs!
|
||||
-}
|
||||
id : String -> Attribute value msg
|
||||
id id_ =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | id = Just id_ }
|
||||
|
||||
|
||||
{-| -}
|
||||
nriDescription : String -> Attribute value msg
|
||||
nriDescription description =
|
||||
custom [ Extra.nriDescription description ]
|
||||
|
||||
|
||||
{-| -}
|
||||
testId : String -> Attribute value msg
|
||||
testId id_ =
|
||||
custom [ Extra.testId id_ ]
|
||||
|
||||
|
||||
{-| Uses the "Writing" input style.
|
||||
-}
|
||||
writing : Attribute value msg
|
||||
writing =
|
||||
Attribute emptyEventsAndValues <|
|
||||
\config -> { config | inputStyle = InputStyles.Writing }
|
||||
|
||||
|
||||
{-| Customizations for the TextInput.
|
||||
-}
|
||||
type Attribute value msg
|
||||
= Attribute (EventsAndValues value msg) (Config -> Config)
|
||||
|
||||
|
||||
type alias EventsAndValues value msg =
|
||||
{ currentValue : Maybe value
|
||||
, toString : Maybe (value -> String)
|
||||
, fromString : Maybe (String -> value)
|
||||
, onInput : Maybe (String -> msg)
|
||||
, onFocus : Maybe msg
|
||||
, onBlur : Maybe msg
|
||||
, onEnter : Maybe msg
|
||||
, floatingContent : Maybe (FloatingContentConfig msg -> Html msg)
|
||||
}
|
||||
|
||||
|
||||
emptyEventsAndValues : EventsAndValues value msg
|
||||
emptyEventsAndValues =
|
||||
{ currentValue = Nothing
|
||||
, toString = Nothing
|
||||
, fromString = Nothing
|
||||
, onFocus = Nothing
|
||||
, onBlur = Nothing
|
||||
, onEnter = Nothing
|
||||
, onInput = Nothing
|
||||
, floatingContent = Nothing
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
map : (a -> b) -> (b -> String) -> Attribute a msg -> Attribute b msg
|
||||
map f toString (Attribute eventsAndValues configF) =
|
||||
Attribute
|
||||
{ currentValue = Maybe.map f eventsAndValues.currentValue
|
||||
, toString = Just toString
|
||||
, fromString = Maybe.map (\from -> from >> f) eventsAndValues.fromString
|
||||
, onFocus = eventsAndValues.onFocus
|
||||
, onBlur = eventsAndValues.onBlur
|
||||
, onEnter = eventsAndValues.onEnter
|
||||
, onInput = eventsAndValues.onInput
|
||||
, floatingContent = eventsAndValues.floatingContent
|
||||
}
|
||||
configF
|
||||
|
||||
|
||||
{-| This is private. The public API only exposes `Attribute`.
|
||||
-}
|
||||
type alias Config =
|
||||
{ inputStyle : InputStyles.Theme
|
||||
, inputCss : List Css.Style
|
||||
, guidance : Maybe String
|
||||
, error : ErrorState
|
||||
, disabled : Bool
|
||||
, loading : Bool
|
||||
, hideLabel : Bool
|
||||
, placeholder : Maybe String
|
||||
, autofocus : Bool
|
||||
, noMarginTop : Bool
|
||||
, containerCss : List Css.Style
|
||||
, id : Maybe String
|
||||
, custom : List (Html.Attribute Never)
|
||||
, fieldType : Maybe String
|
||||
, inputMode : Maybe String
|
||||
, autocomplete : Maybe String
|
||||
}
|
||||
|
||||
|
||||
emptyConfig : Config
|
||||
emptyConfig =
|
||||
{ inputStyle = InputStyles.Standard
|
||||
, inputCss = []
|
||||
, guidance = Nothing
|
||||
, error = InputErrorInternal.init
|
||||
, disabled = False
|
||||
, loading = False
|
||||
, hideLabel = False
|
||||
, placeholder = Nothing
|
||||
, autofocus = False
|
||||
, id = Nothing
|
||||
, noMarginTop = False
|
||||
, containerCss = []
|
||||
, custom = []
|
||||
, fieldType = Nothing
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Nothing
|
||||
}
|
||||
|
||||
|
||||
applyConfig : List (Attribute value msg) -> Config
|
||||
applyConfig attributes =
|
||||
List.foldl (\(Attribute _ update) config -> update config)
|
||||
emptyConfig
|
||||
attributes
|
||||
|
||||
|
||||
orExisting : (acc -> Maybe a) -> acc -> acc -> Maybe a
|
||||
orExisting f new previous =
|
||||
case f previous of
|
||||
Just just ->
|
||||
Just just
|
||||
|
||||
Nothing ->
|
||||
f new
|
||||
|
||||
|
||||
applyEvents : List (Attribute value msg) -> EventsAndValues value msg
|
||||
applyEvents =
|
||||
List.foldl
|
||||
(\(Attribute eventsAndValues _) existing ->
|
||||
{ currentValue = orExisting .currentValue eventsAndValues existing
|
||||
, toString = orExisting .toString eventsAndValues existing
|
||||
, fromString = orExisting .fromString eventsAndValues existing
|
||||
, onFocus = orExisting .onFocus eventsAndValues existing
|
||||
, onBlur = orExisting .onBlur eventsAndValues existing
|
||||
, floatingContent = orExisting .floatingContent eventsAndValues existing
|
||||
, onEnter = orExisting .onEnter eventsAndValues existing
|
||||
, onInput = orExisting .onInput eventsAndValues existing
|
||||
}
|
||||
)
|
||||
emptyEventsAndValues
|
||||
|
||||
|
||||
{-| Render the TextInput as HTML.
|
||||
-}
|
||||
view : String -> List (Attribute value msg) -> Html msg
|
||||
view label attributes =
|
||||
let
|
||||
config : Config
|
||||
config =
|
||||
applyConfig attributes
|
||||
|
||||
eventsAndValues : EventsAndValues value msg
|
||||
eventsAndValues =
|
||||
applyEvents attributes
|
||||
|
||||
idValue =
|
||||
case config.id of
|
||||
Just id_ ->
|
||||
id_
|
||||
|
||||
Nothing ->
|
||||
generateId label
|
||||
|
||||
placeholder_ =
|
||||
config.placeholder
|
||||
|> Maybe.withDefault label
|
||||
|
||||
isInError =
|
||||
InputErrorInternal.getIsInError config.error
|
||||
|
||||
errorMessage_ =
|
||||
InputErrorInternal.getErrorMessage config.error
|
||||
|
||||
( opacity, disabled_ ) =
|
||||
case ( config.disabled, config.loading ) of
|
||||
( False, False ) ->
|
||||
( num 1, False )
|
||||
|
||||
( False, True ) ->
|
||||
( num 0.5, True )
|
||||
|
||||
( True, _ ) ->
|
||||
( num 0.4, True )
|
||||
|
||||
maybeStep =
|
||||
case config.fieldType of
|
||||
Just "number" ->
|
||||
[ step "any" ]
|
||||
|
||||
_ ->
|
||||
[]
|
||||
|
||||
maybeAttr attr maybeValue =
|
||||
maybeValue
|
||||
|> Maybe.map attr
|
||||
|> Maybe.withDefault Extra.none
|
||||
|
||||
stringValue =
|
||||
eventsAndValues.currentValue
|
||||
|> Maybe.map2 identity eventsAndValues.toString
|
||||
|> Maybe.withDefault ""
|
||||
|
||||
onEnter_ : msg -> Html.Attribute msg
|
||||
onEnter_ msg =
|
||||
(\event ->
|
||||
case event.key of
|
||||
Just "Enter" ->
|
||||
Just msg
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
)
|
||||
|> Keyboard.Event.considerKeyboardEvent
|
||||
|> Events.on "keydown"
|
||||
in
|
||||
div
|
||||
[ Attributes.css
|
||||
(position relative
|
||||
:: Css.opacity opacity
|
||||
:: config.containerCss
|
||||
)
|
||||
]
|
||||
[ input
|
||||
(maybeStep
|
||||
++ List.map (Attributes.map never) (List.reverse config.custom)
|
||||
++ [ Attributes.id idValue
|
||||
, case ( errorMessage_, config.guidance ) of
|
||||
( Nothing, Just _ ) ->
|
||||
Aria.describedBy [ idValue ++ "_guidance" ]
|
||||
|
||||
_ ->
|
||||
Extra.none
|
||||
, Attributes.css
|
||||
[ InputStyles.input config.inputStyle isInError
|
||||
, if config.inputStyle == InputStyles.Writing then
|
||||
Css.Global.withClass "override-sass-styles"
|
||||
[ textAlign center
|
||||
, Css.height Css.auto
|
||||
]
|
||||
|
||||
else
|
||||
Css.Global.withClass "override-sass-styles"
|
||||
[ Css.height (px 45)
|
||||
]
|
||||
, Css.pseudoElement "-webkit-search-cancel-button"
|
||||
[ Css.display Css.none ]
|
||||
, if config.noMarginTop then
|
||||
Css.important (Css.marginTop Css.zero)
|
||||
|
||||
else
|
||||
Css.batch []
|
||||
, Css.batch config.inputCss |> Css.important
|
||||
]
|
||||
, Attributes.placeholder placeholder_
|
||||
, Attributes.value stringValue
|
||||
, Attributes.disabled disabled_
|
||||
, maybeAttr Events.onInput eventsAndValues.onInput
|
||||
, maybeAttr Events.onFocus eventsAndValues.onFocus
|
||||
, maybeAttr Events.onBlur eventsAndValues.onBlur
|
||||
, Attributes.autofocus config.autofocus
|
||||
, maybeAttr type_ config.fieldType
|
||||
, maybeAttr (attribute "inputmode") config.inputMode
|
||||
, maybeAttr (attribute "autocomplete") config.autocomplete
|
||||
, maybeAttr onEnter_ eventsAndValues.onEnter
|
||||
, class "override-sass-styles"
|
||||
, Attributes.attribute "aria-invalid" <|
|
||||
if isInError then
|
||||
"true"
|
||||
|
||||
else
|
||||
"false"
|
||||
]
|
||||
)
|
||||
[]
|
||||
, InputLabelInternal.view
|
||||
{ for = idValue
|
||||
, label = label
|
||||
, theme = config.inputStyle
|
||||
}
|
||||
config
|
||||
, Maybe.map2
|
||||
(\view_ onStringInput_ ->
|
||||
view_
|
||||
{ label = label
|
||||
, stringValue = stringValue
|
||||
, onInput = onStringInput_
|
||||
, noMarginTop = config.noMarginTop
|
||||
}
|
||||
)
|
||||
eventsAndValues.floatingContent
|
||||
eventsAndValues.onInput
|
||||
|> Maybe.withDefault (Html.text "")
|
||||
, case ( errorMessage_, config.guidance ) of
|
||||
( Just m, _ ) ->
|
||||
Message.view
|
||||
[ Message.tiny
|
||||
, Message.error
|
||||
, Message.plaintext m
|
||||
, Message.alertRole
|
||||
]
|
||||
|
||||
( _, Just guidanceMessage ) ->
|
||||
Text.caption
|
||||
[ Text.id (idValue ++ "_guidance")
|
||||
, Text.plaintext guidanceMessage
|
||||
, -- Match the vertical styles of the error message
|
||||
Text.css
|
||||
[ Css.paddingTop (Css.px 6)
|
||||
, Css.paddingBottom (Css.px 8)
|
||||
, Css.lineHeight (Css.px 23)
|
||||
]
|
||||
]
|
||||
|
||||
_ ->
|
||||
Html.text ""
|
||||
]
|
||||
|
||||
|
||||
{-| Gives you the default DOM element id that will be used by a `TextInput.view` with the given label.
|
||||
This is for use when you need the DOM element id for use in javascript (such as trigger an event to focus a particular text input)
|
||||
-}
|
||||
generateId : String -> String
|
||||
generateId labelText =
|
||||
"Nri-Ui-TextInput-" ++ dashify labelText
|
||||
|
||||
|
||||
type alias FloatingContentConfig msg =
|
||||
{ label : String
|
||||
, stringValue : String
|
||||
, onInput : String -> msg
|
||||
, noMarginTop : Bool
|
||||
}
|
||||
|
||||
|
||||
viewSearchFloatingContent : FloatingContentConfig msg -> Html msg
|
||||
viewSearchFloatingContent config =
|
||||
if config.stringValue == "" then
|
||||
searchIcon config
|
||||
|
||||
else
|
||||
resetButton config
|
||||
|
||||
|
||||
searchIcon : { settings | noMarginTop : Bool } -> Html msg
|
||||
searchIcon config =
|
||||
UiIcon.search
|
||||
|> Svg.withWidth (Css.px 20)
|
||||
|> Svg.withHeight (Css.px 20)
|
||||
|> Svg.withColor Colors.gray75
|
||||
|> Svg.withCss
|
||||
[ Css.position Css.absolute
|
||||
, Css.right (Css.px 10)
|
||||
, if config.noMarginTop then
|
||||
Css.top (Css.px (22 - defaultMarginTop))
|
||||
|
||||
else
|
||||
Css.top (Css.px 22)
|
||||
]
|
||||
|> Svg.toHtml
|
||||
|
||||
|
||||
resetButton : FloatingContentConfig msg -> Html msg
|
||||
resetButton config =
|
||||
ClickableSvg.button ("Reset " ++ config.label)
|
||||
UiIcon.x
|
||||
[ ClickableSvg.onClick (config.onInput "")
|
||||
, ClickableSvg.exactWidth 14
|
||||
, ClickableSvg.exactHeight 14
|
||||
, ClickableSvg.css
|
||||
[ Css.position Css.absolute
|
||||
, Css.right (Css.px 10)
|
||||
, if config.noMarginTop then
|
||||
Css.top (Css.px (25 - defaultMarginTop))
|
||||
|
||||
else
|
||||
Css.top (Css.px 25)
|
||||
]
|
||||
, ClickableSvg.custom [ Attributes.type_ "button" ]
|
||||
]
|
||||
|
||||
|
||||
viewPasswordFloatingContent : String -> msg -> FloatingContentConfig msg -> Html msg
|
||||
viewPasswordFloatingContent label toggle config =
|
||||
if config.stringValue == "" then
|
||||
Html.text ""
|
||||
|
||||
else
|
||||
-- TODO: consider using a "toggle" clickable text button,
|
||||
-- a checkbox styled to look like a clickable text, or
|
||||
-- adding additional aria attributes connecting this clickable
|
||||
-- text to the password field.
|
||||
ClickableText.button label
|
||||
[ ClickableText.onClick toggle
|
||||
, ClickableText.small
|
||||
, ClickableText.css
|
||||
[ Css.position Css.absolute
|
||||
, Css.right (Css.px 15)
|
||||
, if config.noMarginTop then
|
||||
Css.top (Css.px (22 - defaultMarginTop))
|
||||
|
||||
else
|
||||
Css.top (Css.px 22)
|
||||
, Css.fontSize (Css.px 13)
|
||||
]
|
||||
, ClickableText.custom [ Attributes.type_ "button" ]
|
||||
]
|
@ -26,6 +26,7 @@ Post-release patches:
|
||||
- mark customTriggerAttributes as deprecated
|
||||
- add containerCss
|
||||
- adds `nriDescription` and `testId`
|
||||
- fix <https://github.com/NoRedInk/noredink-ui/issues/766>
|
||||
|
||||
Changes from V1:
|
||||
|
||||
@ -106,6 +107,7 @@ type Attribute msg
|
||||
|
||||
type alias Tooltip msg =
|
||||
{ direction : Direction
|
||||
, alignment : Alignment
|
||||
, tail : Tail
|
||||
, content : List (Html msg)
|
||||
, attributes : List (Html.Attribute Never)
|
||||
@ -126,7 +128,8 @@ buildAttributes =
|
||||
defaultTooltip : Tooltip msg
|
||||
defaultTooltip =
|
||||
{ direction = OnTop
|
||||
, tail = WithTail Middle
|
||||
, alignment = Middle
|
||||
, tail = WithTail
|
||||
, content = []
|
||||
, attributes = []
|
||||
, containerStyles =
|
||||
@ -160,7 +163,7 @@ html content =
|
||||
|
||||
|
||||
type Tail
|
||||
= WithTail Alignment
|
||||
= WithTail
|
||||
| WithoutTail
|
||||
|
||||
|
||||
@ -173,10 +176,6 @@ type Alignment
|
||||
|
||||
|
||||
{-| Makes it so that the tooltip does not have a tail!
|
||||
|
||||
This will center the tooltip relative to the trigger content, superseding any
|
||||
custom alignment set by `alignStart` and `alignEnd`.
|
||||
|
||||
-}
|
||||
withoutTail : Attribute msg
|
||||
withoutTail =
|
||||
@ -185,17 +184,7 @@ withoutTail =
|
||||
|
||||
withAligment : Alignment -> Attribute msg
|
||||
withAligment alignment =
|
||||
Attribute (\config -> { config | tail = WithTail alignment })
|
||||
|
||||
|
||||
tailAlignment : Tail -> Alignment
|
||||
tailAlignment tail =
|
||||
case tail of
|
||||
WithTail alignment ->
|
||||
alignment
|
||||
|
||||
WithoutTail ->
|
||||
Middle
|
||||
Attribute (\config -> { config | alignment = alignment })
|
||||
|
||||
|
||||
{-| Put the tail at the "start" of the tooltip.
|
||||
@ -664,7 +653,7 @@ viewOpenTooltip tooltipId config =
|
||||
Html.div
|
||||
[ Attributes.css
|
||||
[ Css.position Css.absolute
|
||||
, positionTooltip config.direction (tailAlignment config.tail)
|
||||
, positionTooltip config.direction config.alignment
|
||||
, Css.boxSizing Css.borderBox
|
||||
]
|
||||
]
|
||||
@ -684,7 +673,7 @@ viewOpenTooltip tooltipId config =
|
||||
]
|
||||
++ config.tooltipStyleOverrides
|
||||
)
|
||||
, pointerBox config.tail config.direction (tailAlignment config.tail)
|
||||
, pointerBox config.tail config.direction config.alignment
|
||||
|
||||
-- We need to keep this animation in tests to make it pass: check out
|
||||
-- the NoAnimations middleware. So if you change the name here, please
|
||||
@ -771,7 +760,7 @@ pointerBox tail direction alignment =
|
||||
, Css.border3 (Css.px 1) Css.solid Colors.navy
|
||||
, positioning direction alignment
|
||||
, case tail of
|
||||
WithTail _ ->
|
||||
WithTail ->
|
||||
tailForDirection direction
|
||||
|
||||
WithoutTail ->
|
||||
|
@ -209,14 +209,15 @@ performance =
|
||||
, Attributes.fill "currentcolor"
|
||||
, Attributes.viewBox "0 0 30 30"
|
||||
]
|
||||
[ Svg.polygon [ Attributes.points "22.1,24.6 22.1,8.4 17.8,7.1 17.8,24.6 " ] []
|
||||
, Svg.polygon [ Attributes.points "24.2,7.7 24.2,24.6 28.5,24.6 28.5,5 26.3,3.5 " ] []
|
||||
, Svg.polygon [ Attributes.points "5,15.6 5,24.6 9.3,24.6 9.3,12.3 5.8,16.5 " ] []
|
||||
, Svg.polygon [ Attributes.points "11.4,24.6 15.7,24.6 15.7,6.5 14.5,6.2 11.4,9.8 " ] []
|
||||
, Svg.path [ Attributes.fill "none", Attributes.d "M33.6,26.9H30v1.2c0,1.6-0.4,1.8-1.8,1.8H1.8C0.4,30,0,29.7,0,28.2V1.9c0-1.4,0.3-1.8,1.8-1.8H3v-5.5h30.6V26.9z" ] []
|
||||
, Svg.path [ Attributes.d "M3.1,26.9V3.2V0.1H1.8C0.3,0.1,0,0.5,0,1.9v26.2C0,29.7,0.4,30,1.8,30h26.3c1.5,0,1.8-0.3,1.8-1.8V27h-3.1H3.1V26.9z" ] []
|
||||
, Svg.path [ Attributes.fill "none", Attributes.d "M-715-401V715H309V-401H-715z" ] []
|
||||
, Svg.path [ Attributes.fill "none", Attributes.d "M-737.2-385.9v1116h1024v-1116L-737.2-385.9L-737.2-385.9z" ] []
|
||||
[ Svg.path
|
||||
[ Attributes.d "M2.575,22.5 L2.55333333,2.47096774 L2.55333333,5.68434189e-14 L1.53166667,5.68434189e-14 C0.275833333,5.68434189e-14 0,0.345967742 0,1.48225806 L0.0216666667,23.4887097 C0.0216666667,24.7185484 0.3275,24.9709677 1.55333333,24.9709677 L23.4891667,24.9709677 C24.7191667,24.9709677 25.0216667,24.7483871 25.0216667,23.4887097 L25.0216667,22.5 L22.4675,22.5 L2.575,22.5 Z" ]
|
||||
[]
|
||||
, Svg.rect
|
||||
[ Attributes.x "4.224", Attributes.y "11.9331996", Attributes.width "3.55583333", Attributes.height "9.42432817", Attributes.rx "1" ]
|
||||
[]
|
||||
, Svg.rect [ Attributes.x "9.47510076", Attributes.y "5.31243234", Attributes.width "3.55583333", Attributes.height "16.0450955", Attributes.rx "1" ] []
|
||||
, Svg.rect [ Attributes.x "14.7262015", Attributes.y "8.69585911", Attributes.width "3.55583333", Attributes.height "12.6616687", Attributes.rx "1" ] []
|
||||
, Svg.rect [ Attributes.x "19.9773023", Attributes.y "3.19919812", Attributes.width "3.55583333", Attributes.height "18.1583297", Attributes.rx "1" ] []
|
||||
]
|
||||
|> Nri.Ui.Svg.V1.fromHtml
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
module CommonControls exposing (httpError)
|
||||
module CommonControls exposing (exampleHtml, httpError, quickBrownFox, romeoAndJulietQuotation)
|
||||
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Http
|
||||
|
||||
|
||||
@ -38,3 +40,42 @@ httpError =
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
quickBrownFox : String
|
||||
quickBrownFox =
|
||||
"The quick brown fox jumps over the lazy dog."
|
||||
|
||||
|
||||
romeoAndJulietQuotation : String
|
||||
romeoAndJulietQuotation =
|
||||
"""
|
||||
Two households, both alike in dignity,
|
||||
In fair Verona, where we lay our scene,
|
||||
From ancient grudge break to new mutiny,
|
||||
Where civil blood makes civil hands unclean.
|
||||
From forth the fatal loins of these two foes
|
||||
A pair of star-cross’d lovers take their life;
|
||||
Whose misadventured piteous overthrows
|
||||
Do with their death bury their parents’ strife.
|
||||
The fearful passage of their death-mark’d love,
|
||||
And the continuance of their parents’ rage,
|
||||
Which, but their children’s end, nought could remove,
|
||||
Is now the two hours’ traffic of our stage;
|
||||
The which if you with patient ears attend,
|
||||
What here shall miss, our toil shall strive to mend.
|
||||
"""
|
||||
|
||||
|
||||
exampleHtml : List (Html msg)
|
||||
exampleHtml =
|
||||
[ Html.text "This is a "
|
||||
, Html.strong [] [ Html.text "bolded phrase" ]
|
||||
, Html.text ". "
|
||||
, Html.a
|
||||
[ Attributes.href "http://www.noredink.com"
|
||||
, Attributes.target "_blank"
|
||||
]
|
||||
[ Html.text quickBrownFox ]
|
||||
, Html.text " When I stepped out, into the bright sunlight from the darkness of the movie house, I had only two things on my mind: Paul Newman, and a ride home."
|
||||
]
|
||||
|
@ -1,15 +1,22 @@
|
||||
module Example exposing (Example, view, wrapMsg, wrapState)
|
||||
module Example exposing (Example, preview, view, wrapMsg, wrapState)
|
||||
|
||||
import Category exposing (Category)
|
||||
import Css exposing (..)
|
||||
import Css.Global exposing (a, descendants)
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Html.Styled.Events as Events
|
||||
import Html.Styled.Lazy as Lazy
|
||||
import KeyboardSupport exposing (KeyboardSupport)
|
||||
import Nri.Ui.Colors.V1 exposing (..)
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors exposing (..)
|
||||
import Nri.Ui.Container.V2 as Container
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Html.Attributes.V2 as AttributeExtras exposing (targetBlank)
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Routes exposing (Route)
|
||||
|
||||
|
||||
type alias Example state msg =
|
||||
@ -18,12 +25,18 @@ type alias Example state msg =
|
||||
, state : state
|
||||
, update : msg -> state -> ( state, Cmd msg )
|
||||
, subscriptions : state -> Sub msg
|
||||
, preview : List (Html Never)
|
||||
, view : state -> List (Html msg)
|
||||
, categories : List Category
|
||||
, keyboardSupport : List KeyboardSupport
|
||||
}
|
||||
|
||||
|
||||
fullName : Example state msg -> String
|
||||
fullName example =
|
||||
"Nri.Ui." ++ example.name ++ ".V" ++ String.fromInt example.version
|
||||
|
||||
|
||||
wrapMsg :
|
||||
(msg -> msg2)
|
||||
-> (msg2 -> Maybe msg)
|
||||
@ -43,6 +56,7 @@ wrapMsg wrapMsg_ unwrapMsg example =
|
||||
Nothing ->
|
||||
( state, Cmd.none )
|
||||
, subscriptions = \state -> Sub.map wrapMsg_ (example.subscriptions state)
|
||||
, preview = example.preview
|
||||
, view = \state -> List.map (Html.map wrapMsg_) (example.view state)
|
||||
, categories = example.categories
|
||||
, keyboardSupport = example.keyboardSupport
|
||||
@ -71,6 +85,7 @@ wrapState wrapState_ unwrapState example =
|
||||
unwrapState
|
||||
>> Maybe.map example.subscriptions
|
||||
>> Maybe.withDefault Sub.none
|
||||
, preview = example.preview
|
||||
, view =
|
||||
unwrapState
|
||||
>> Maybe.map example.view
|
||||
@ -80,22 +95,77 @@ wrapState wrapState_ unwrapState example =
|
||||
}
|
||||
|
||||
|
||||
view : Example state msg -> Html msg
|
||||
view =
|
||||
Lazy.lazy view_
|
||||
preview : (Route -> msg2) -> Example state msg -> Html msg2
|
||||
preview navigate =
|
||||
Lazy.lazy (preview_ navigate)
|
||||
|
||||
|
||||
preview_ : (Route -> msg2) -> Example state msg -> Html msg2
|
||||
preview_ navigate example =
|
||||
Container.view
|
||||
[ Container.gray
|
||||
, Container.css
|
||||
[ Css.flexBasis (Css.px 150)
|
||||
, Css.hover
|
||||
[ Css.backgroundColor Colors.glacier
|
||||
, Css.cursor Css.pointer
|
||||
]
|
||||
]
|
||||
, Container.custom [ Events.onClick (navigate (Routes.Doodad example.name)) ]
|
||||
, Container.html
|
||||
(ClickableText.link example.name
|
||||
[ ClickableText.href (exampleHref example)
|
||||
, ClickableText.css [ Css.marginBottom (Css.px 10) ]
|
||||
]
|
||||
:: [ Html.div
|
||||
[ Attributes.css
|
||||
[ Css.displayFlex
|
||||
, Css.flexDirection Css.column
|
||||
]
|
||||
]
|
||||
(List.map (Html.map never) example.preview)
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
view : Maybe Route -> Example state msg -> Html msg
|
||||
view previousRoute example =
|
||||
Container.view
|
||||
[ Container.pillow
|
||||
, Container.css
|
||||
[ Css.position Css.relative
|
||||
, Css.margin (Css.px 10)
|
||||
, Css.minHeight (Css.calc (Css.vh 100) Css.minus (Css.px 20))
|
||||
, Css.boxSizing Css.borderBox
|
||||
]
|
||||
, Container.html
|
||||
[ Lazy.lazy view_ example
|
||||
, ClickableSvg.link ("Close " ++ example.name ++ " example")
|
||||
UiIcon.x
|
||||
[ ClickableSvg.href
|
||||
(Maybe.withDefault Routes.All previousRoute
|
||||
|> Routes.toString
|
||||
)
|
||||
, ClickableSvg.small
|
||||
, ClickableSvg.css
|
||||
[ Css.position Css.absolute
|
||||
, Css.top (Css.px 15)
|
||||
, Css.right (Css.px 15)
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
view_ : Example state msg -> Html msg
|
||||
view_ example =
|
||||
let
|
||||
fullName =
|
||||
"Nri.Ui." ++ example.name ++ ".V" ++ String.fromInt example.version
|
||||
in
|
||||
Html.div
|
||||
[ -- this class makes the axe accessibility checking output easier to parse
|
||||
String.replace "." "-" example.name
|
||||
|> (++) "module-example__"
|
||||
|> Attributes.class
|
||||
, Attributes.id (String.replace "." "-" example.name)
|
||||
]
|
||||
[ Html.div
|
||||
[ Attributes.css
|
||||
@ -107,52 +177,57 @@ view_ example =
|
||||
, descendants [ Css.Global.a [ textDecoration none ] ]
|
||||
]
|
||||
]
|
||||
[ Html.styled Html.h2
|
||||
[ color navy
|
||||
, fontSize (px 20)
|
||||
, marginTop zero
|
||||
, marginBottom zero
|
||||
, Fonts.baseFont
|
||||
]
|
||||
[]
|
||||
[ Html.a
|
||||
[ Attributes.href ("#/doodad/" ++ example.name)
|
||||
, Attributes.class "module-example__doodad-link"
|
||||
, -- this data attribute is used to name the Percy screenshots
|
||||
String.replace "." "-" example.name
|
||||
|> Attributes.attribute "data-percy-name"
|
||||
]
|
||||
[ Html.text fullName ]
|
||||
]
|
||||
, String.replace "." "-" fullName
|
||||
|> (++) "https://package.elm-lang.org/packages/NoRedInk/noredink-ui/latest/"
|
||||
|> viewLink "Docs"
|
||||
, String.replace "." "/" fullName
|
||||
++ ".elm"
|
||||
|> (++) "https://github.com/NoRedInk/noredink-ui/blob/master/src/"
|
||||
|> viewLink "Source"
|
||||
[ exampleLink example
|
||||
, docsLink example
|
||||
, srcLink example
|
||||
]
|
||||
, KeyboardSupport.view example.keyboardSupport
|
||||
, Html.div
|
||||
[ Attributes.css
|
||||
[ padding (px 40)
|
||||
, boxShadow5 zero (px 2) (px 4) zero (rgba 0 0 0 0.25)
|
||||
, border3 (px 1) solid gray92
|
||||
, borderRadius (px 20)
|
||||
, margin3 (px 10) zero (px 40)
|
||||
, Html.div [] (example.view example.state)
|
||||
]
|
||||
|
||||
|
||||
exampleHref : Example state msg -> String
|
||||
exampleHref example =
|
||||
Routes.toString (Routes.Doodad example.name)
|
||||
|
||||
|
||||
exampleLink : Example state msg -> Html msg
|
||||
exampleLink example =
|
||||
Heading.h2 []
|
||||
[ ClickableText.link (fullName example)
|
||||
[ ClickableText.href (exampleHref example)
|
||||
, ClickableText.large
|
||||
, ClickableText.custom
|
||||
[ -- this data attribute is used to name the Percy screenshots
|
||||
String.replace "." "-" example.name
|
||||
|> Attributes.attribute "data-percy-name"
|
||||
]
|
||||
]
|
||||
(example.view example.state)
|
||||
]
|
||||
|
||||
|
||||
viewLink : String -> String -> Html msg
|
||||
viewLink text href =
|
||||
Html.a
|
||||
([ Attributes.href href
|
||||
, Attributes.css [ Css.display Css.block, marginLeft (px 20) ]
|
||||
]
|
||||
++ targetBlank
|
||||
)
|
||||
[ Html.text text
|
||||
docsLink : Example state msg -> Html msg
|
||||
docsLink example =
|
||||
let
|
||||
link =
|
||||
"https://package.elm-lang.org/packages/NoRedInk/noredink-ui/latest/"
|
||||
++ String.replace "." "-" (fullName example)
|
||||
in
|
||||
ClickableText.link "Docs"
|
||||
[ ClickableText.linkExternal link
|
||||
, ClickableText.css [ Css.marginLeft (Css.px 20) ]
|
||||
]
|
||||
|
||||
|
||||
srcLink : Example state msg -> Html msg
|
||||
srcLink example =
|
||||
let
|
||||
link =
|
||||
String.replace "." "/" (fullName example)
|
||||
++ ".elm"
|
||||
|> (++) "https://github.com/NoRedInk/noredink-ui/blob/master/src/"
|
||||
in
|
||||
ClickableText.link "Source"
|
||||
[ ClickableText.linkExternal link
|
||||
, ClickableText.css [ Css.marginLeft (Css.px 20) ]
|
||||
]
|
||||
|
@ -25,6 +25,7 @@ import Nri.Ui.DisclosureIndicator.V2 as DisclosureIndicator
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Set exposing (Set)
|
||||
import Task
|
||||
@ -38,6 +39,21 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ -- faking a mini version of the Accordion component to give styleguide users a sense of what the
|
||||
-- component might look like
|
||||
Html.div []
|
||||
[ Html.div [ css [ Css.displayFlex, Css.alignItems Css.center ] ]
|
||||
[ defaultCaret False
|
||||
, Text.smallBody [ Text.plaintext "Closed" ]
|
||||
]
|
||||
, Html.div [ css [ Css.displayFlex, Css.alignItems Css.center ] ]
|
||||
[ defaultCaret True
|
||||
, Text.smallBody [ Text.plaintext "Open" ]
|
||||
]
|
||||
, Text.caption [ Text.plaintext "Accordion content." ]
|
||||
]
|
||||
]
|
||||
, view = view
|
||||
, categories = [ Layout ]
|
||||
, keyboardSupport =
|
||||
@ -57,13 +73,14 @@ example =
|
||||
}
|
||||
|
||||
|
||||
defaultCaret : Bool -> Html msg
|
||||
defaultCaret =
|
||||
DisclosureIndicator.large [ Css.marginRight (Css.px 8) ]
|
||||
|
||||
|
||||
{-| -}
|
||||
view : State -> List (Html Msg)
|
||||
view model =
|
||||
let
|
||||
defaultCaret =
|
||||
DisclosureIndicator.large [ Css.marginRight (Css.px 8) ]
|
||||
in
|
||||
[ Heading.h3 [] [ Html.text "Accordion.view" ]
|
||||
, Accordion.view
|
||||
{ entries =
|
||||
|
@ -33,6 +33,21 @@ example =
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
IconExamples.preview
|
||||
[ AssignmentIcon.planningDiagnosticCircled
|
||||
, AssignmentIcon.unitDiagnosticCircled
|
||||
, AssignmentIcon.practiceCircled
|
||||
, AssignmentIcon.quizCircled
|
||||
, AssignmentIcon.quickWriteCircled
|
||||
, AssignmentIcon.guidedDraftCircled
|
||||
, AssignmentIcon.peerReviewCircled
|
||||
, AssignmentIcon.selfReviewCircled
|
||||
, AssignmentIcon.startPrimary
|
||||
, AssignmentIcon.assessment
|
||||
, AssignmentIcon.standards
|
||||
, AssignmentIcon.writing
|
||||
]
|
||||
, view =
|
||||
\_ ->
|
||||
[ IconExamples.view "Diagnostic"
|
||||
|
@ -29,32 +29,39 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ Balloon.balloon
|
||||
[ Balloon.onTop
|
||||
, Balloon.navy
|
||||
, Balloon.paddingPx 15
|
||||
]
|
||||
(text "This is a balloon.")
|
||||
]
|
||||
, view = view
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias State =
|
||||
Control Settings
|
||||
|
||||
|
||||
type alias Settings =
|
||||
{ copy : String
|
||||
, theme : Maybe ( String, Balloon.Attribute )
|
||||
, position : Maybe ( String, Balloon.Attribute )
|
||||
, width : Maybe ( String, Balloon.Attribute )
|
||||
, padding : Maybe ( String, Balloon.Attribute )
|
||||
{ copy : Control String
|
||||
, attributes : Control (List ( String, Balloon.Attribute ))
|
||||
}
|
||||
|
||||
|
||||
init : Control Settings
|
||||
init : State
|
||||
init =
|
||||
Control.record Settings
|
||||
|> Control.field "copy" (Control.string "Hello, world!")
|
||||
|> Control.field "theme" (Control.maybe False themeOptions)
|
||||
|> Control.field "position" (Control.maybe False positionOptions)
|
||||
|> Control.field "width" (Control.maybe False widthOptions)
|
||||
|> Control.field "padding" (Control.maybe False paddingOptions)
|
||||
{ copy = Control.string "Hello, world!"
|
||||
, attributes = controlAttributes
|
||||
}
|
||||
|
||||
|
||||
controlAttributes : Control (List ( String, Balloon.Attribute ))
|
||||
controlAttributes =
|
||||
ControlExtra.list
|
||||
|> ControlExtra.optionalListItem "theme" themeOptions
|
||||
|> ControlExtra.optionalListItem "position" positionOptions
|
||||
|> ControlExtra.optionalListItem "width" widthOptions
|
||||
|> ControlExtra.optionalListItem "padding" paddingOptions
|
||||
|
||||
|
||||
themeOptions : Control ( String, Balloon.Attribute )
|
||||
@ -103,14 +110,20 @@ paddingOptions =
|
||||
|
||||
{-| -}
|
||||
type Msg
|
||||
= SetDebugControlsState (Control Settings)
|
||||
= SetCopy (Control String)
|
||||
| SetAttributes (Control (List ( String, Balloon.Attribute )))
|
||||
|
||||
|
||||
update : Msg -> State -> ( State, Cmd Msg )
|
||||
update msg state =
|
||||
case msg of
|
||||
SetDebugControlsState newDebugControlsState ->
|
||||
( newDebugControlsState
|
||||
SetCopy copy ->
|
||||
( { state | copy = copy }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
SetAttributes attributes ->
|
||||
( { state | attributes = attributes }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
@ -118,26 +131,22 @@ update msg state =
|
||||
view : State -> List (Html Msg)
|
||||
view state =
|
||||
let
|
||||
settings =
|
||||
Control.currentValue state
|
||||
copy =
|
||||
Control.currentValue state.copy
|
||||
|
||||
attributes =
|
||||
List.filterMap identity
|
||||
[ settings.theme
|
||||
, settings.position
|
||||
, settings.width
|
||||
, settings.padding
|
||||
]
|
||||
Control.currentValue state.attributes
|
||||
in
|
||||
[ Control.view SetDebugControlsState state |> fromUnstyled
|
||||
[ Control.view SetCopy state.copy |> fromUnstyled
|
||||
, Control.view SetAttributes state.attributes |> fromUnstyled
|
||||
, Html.Styled.code [ css [ Css.display Css.block, Css.margin2 (Css.px 20) Css.zero ] ]
|
||||
[ text <|
|
||||
"Balloon.balloon [ "
|
||||
++ String.join ", " (List.map Tuple.first attributes)
|
||||
++ " ] "
|
||||
++ "\""
|
||||
++ settings.copy
|
||||
++ copy
|
||||
++ "\""
|
||||
]
|
||||
, Balloon.balloon (List.map Tuple.second attributes) (text settings.copy)
|
||||
, Balloon.balloon (List.map Tuple.second attributes) (text copy)
|
||||
]
|
||||
|
@ -6,6 +6,7 @@ module Examples.Button exposing (Msg, State, example)
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Category exposing (Category(..))
|
||||
import Css exposing (middle, verticalAlign)
|
||||
import Debug.Control as Control exposing (Control)
|
||||
@ -28,6 +29,27 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ Button.link "Primary"
|
||||
[ Button.small
|
||||
, Button.fillContainerWidth
|
||||
, Button.custom [ Key.tabbable False ]
|
||||
]
|
||||
, Button.link "Secondary"
|
||||
[ Button.small
|
||||
, Button.fillContainerWidth
|
||||
, Button.secondary
|
||||
, Button.css [ Css.marginTop (Css.px 8) ]
|
||||
, Button.custom [ Key.tabbable False ]
|
||||
]
|
||||
, Button.link "Premium"
|
||||
[ Button.small
|
||||
, Button.fillContainerWidth
|
||||
, Button.premium
|
||||
, Button.css [ Css.marginTop (Css.px 8) ]
|
||||
, Button.custom [ Key.tabbable False ]
|
||||
]
|
||||
]
|
||||
, view = \state -> [ viewButtonExamples state ]
|
||||
, categories = [ Buttons ]
|
||||
, keyboardSupport = []
|
||||
|
@ -38,6 +38,7 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview = []
|
||||
, view =
|
||||
\state ->
|
||||
[ viewInteractableCheckbox "styleguide-checkbox-interactable" state
|
||||
|
@ -6,6 +6,7 @@ module Examples.ClickableSvg exposing (Msg, State, example)
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Category exposing (Category(..))
|
||||
import Css
|
||||
import Debug.Control as Control exposing (Control)
|
||||
@ -20,7 +21,6 @@ import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.Colors.Extra exposing (fromCssColor, toCssColor)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Select.V7 as Select
|
||||
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
|
||||
import Nri.Ui.Tooltip.V2 as Tooltip
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
@ -36,6 +36,23 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ ClickableSvg.link "ClickableSvg small"
|
||||
UiIcon.link
|
||||
[ ClickableSvg.small
|
||||
, ClickableSvg.custom [ Key.tabbable False ]
|
||||
]
|
||||
, ClickableSvg.link "ClickableSvg medium"
|
||||
UiIcon.link
|
||||
[ ClickableSvg.medium
|
||||
, ClickableSvg.custom [ Key.tabbable False ]
|
||||
]
|
||||
, ClickableSvg.link "ClickableSvg large"
|
||||
UiIcon.link
|
||||
[ ClickableSvg.large
|
||||
, ClickableSvg.custom [ Key.tabbable False ]
|
||||
]
|
||||
]
|
||||
, view =
|
||||
\state ->
|
||||
let
|
||||
|
@ -6,6 +6,7 @@ module Examples.ClickableText exposing (Msg, State, example)
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Category exposing (Category(..))
|
||||
import Css exposing (middle, verticalAlign)
|
||||
import Debug.Control as Control exposing (Control)
|
||||
@ -15,7 +16,7 @@ import Html.Styled.Attributes exposing (css, id)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
|
||||
@ -32,6 +33,23 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ ClickableText.link "Small"
|
||||
[ ClickableText.icon UiIcon.link
|
||||
, ClickableText.small
|
||||
, ClickableText.custom [ Key.tabbable False ]
|
||||
]
|
||||
, ClickableText.link "Medium"
|
||||
[ ClickableText.icon UiIcon.link
|
||||
, ClickableText.medium
|
||||
, ClickableText.custom [ Key.tabbable False ]
|
||||
]
|
||||
, ClickableText.link "Large"
|
||||
[ ClickableText.icon UiIcon.link
|
||||
, ClickableText.large
|
||||
, ClickableText.custom [ Key.tabbable False ]
|
||||
]
|
||||
]
|
||||
, view = \state -> [ viewExamples state ]
|
||||
, categories = [ Buttons ]
|
||||
, keyboardSupport = []
|
||||
@ -94,21 +112,23 @@ viewExamples (State control) =
|
||||
[ Control.view (State >> SetState) control
|
||||
|> fromUnstyled
|
||||
, buttons model
|
||||
, Text.smallBody []
|
||||
[ text "Sometimes, we'll want our clickable links: "
|
||||
, ClickableText.link model.label
|
||||
[ ClickableText.small
|
||||
, Maybe.map ClickableText.icon model.icon
|
||||
|> Maybe.withDefault (ClickableText.custom [])
|
||||
, Text.smallBody
|
||||
[ Text.html
|
||||
[ text "Sometimes, we'll want our clickable links: "
|
||||
, ClickableText.link model.label
|
||||
[ ClickableText.small
|
||||
, Maybe.map ClickableText.icon model.icon
|
||||
|> Maybe.withDefault (ClickableText.custom [])
|
||||
]
|
||||
, text " and clickable buttons: "
|
||||
, ClickableText.button model.label
|
||||
[ ClickableText.small
|
||||
, ClickableText.onClick (ShowItWorked "ClickableText" "in-line button")
|
||||
, Maybe.map ClickableText.icon model.icon
|
||||
|> Maybe.withDefault (ClickableText.custom [])
|
||||
]
|
||||
, text " to show up in-line."
|
||||
]
|
||||
, text " and clickable buttons: "
|
||||
, ClickableText.button model.label
|
||||
[ ClickableText.small
|
||||
, ClickableText.onClick (ShowItWorked "ClickableText" "in-line button")
|
||||
, Maybe.map ClickableText.icon model.icon
|
||||
|> Maybe.withDefault (ClickableText.custom [])
|
||||
]
|
||||
, text " to show up in-line."
|
||||
]
|
||||
]
|
||||
|> div []
|
||||
|
@ -14,6 +14,7 @@ import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Colors.Extra
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import SolidColor exposing (highContrast)
|
||||
|
||||
@ -41,6 +42,12 @@ example =
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ ( "green", Colors.green )
|
||||
, ( "purple", Colors.purple )
|
||||
, ( "mustard", Colors.mustard )
|
||||
]
|
||||
|> List.map viewPreviewSwatch
|
||||
, view =
|
||||
\_ ->
|
||||
[ [ ( "gray20", Colors.gray20, "Main text" )
|
||||
@ -117,6 +124,22 @@ example =
|
||||
}
|
||||
|
||||
|
||||
viewPreviewSwatch : ( String, Css.Color ) -> Html.Html msg
|
||||
viewPreviewSwatch ( name, color ) =
|
||||
Html.div
|
||||
[ Attributes.css
|
||||
[ Css.textAlign Css.center
|
||||
, Css.padding2 (Css.px 8) Css.zero
|
||||
, Css.margin2 (Css.px 4) Css.zero
|
||||
, Css.borderRadius (Css.px 4)
|
||||
, Css.backgroundColor color
|
||||
, Css.color color
|
||||
, Css.fontSize (Css.px 14)
|
||||
]
|
||||
]
|
||||
[ Html.text name ]
|
||||
|
||||
|
||||
viewColors : List ColorExample -> Html.Html msg
|
||||
viewColors colors =
|
||||
colors
|
||||
|
@ -33,6 +33,7 @@ example =
|
||||
[ Browser.Events.onResize WindowResized
|
||||
, Confetti.subscriptions ConfettiMsg state
|
||||
]
|
||||
, preview = []
|
||||
, view =
|
||||
\state ->
|
||||
[ Button.button "Launch confetti!"
|
||||
|
@ -7,6 +7,7 @@ module Examples.Container exposing (Msg, State, example)
|
||||
-}
|
||||
|
||||
import Category exposing (Category(..))
|
||||
import CommonControls exposing (romeoAndJulietQuotation)
|
||||
import Css
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
@ -20,7 +21,7 @@ import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Container.V2 as Container
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
|
||||
@ -34,6 +35,17 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ Container.view []
|
||||
, Container.view
|
||||
[ Container.invalid
|
||||
, Container.css [ Css.marginTop (Css.px 8) ]
|
||||
]
|
||||
, Container.view
|
||||
[ Container.disabled
|
||||
, Container.css [ Css.marginTop (Css.px 8) ]
|
||||
]
|
||||
]
|
||||
, view =
|
||||
\state ->
|
||||
let
|
||||
@ -149,26 +161,6 @@ controlContent =
|
||||
]
|
||||
|
||||
|
||||
romeoAndJulietQuotation : String
|
||||
romeoAndJulietQuotation =
|
||||
"""
|
||||
Two households, both alike in dignity,
|
||||
In fair Verona, where we lay our scene,
|
||||
From ancient grudge break to new mutiny,
|
||||
Where civil blood makes civil hands unclean.
|
||||
From forth the fatal loins of these two foes
|
||||
A pair of star-cross’d lovers take their life;
|
||||
Whose misadventured piteous overthrows
|
||||
Do with their death bury their parents’ strife.
|
||||
The fearful passage of their death-mark’d love,
|
||||
And the continuance of their parents’ rage,
|
||||
Which, but their children’s end, nought could remove,
|
||||
Is now the two hours’ traffic of our stage;
|
||||
The which if you with patient ears attend,
|
||||
What here shall miss, our toil shall strive to mend.
|
||||
"""
|
||||
|
||||
|
||||
{-| -}
|
||||
type Msg
|
||||
= UpdateControl (Control (List (Container.Attribute Msg)))
|
||||
|
@ -16,7 +16,7 @@ import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.DisclosureIndicator.V2 as DisclosureIndicator
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -36,9 +36,15 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ DisclosureIndicator.medium [] False
|
||||
, DisclosureIndicator.medium [] True
|
||||
, DisclosureIndicator.large [] False
|
||||
, DisclosureIndicator.large [] True
|
||||
]
|
||||
, view =
|
||||
\state ->
|
||||
[ Text.smallBodyGray [] [ Html.text "The disclosure indicator is only the caret. It is NOT a button -- you must create a button or clickabletext yourself!" ]
|
||||
[ Text.smallBodyGray [ Text.plaintext "The disclosure indicator is only the caret. It is NOT a button -- you must create a button or clickabletext yourself!" ]
|
||||
, Html.div [ css [ Css.displayFlex, Css.padding (Css.px 8) ] ]
|
||||
[ Button.button "Toggle large indicator"
|
||||
[ Button.onClick ToggleLarge, Button.small, Button.secondary ]
|
||||
|
@ -35,5 +35,6 @@ example =
|
||||
, state = {}
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview = [ Divider.view "Dividing Line" ]
|
||||
, view = \state -> [ Divider.view "Dividing Line" ]
|
||||
}
|
||||
|
@ -7,8 +7,9 @@ module Examples.Fonts exposing (example, State, Msg)
|
||||
-}
|
||||
|
||||
import Category exposing (Category(..))
|
||||
import Css exposing (Style)
|
||||
import Example exposing (Example)
|
||||
import Html.Styled as Html
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
@ -35,6 +36,12 @@ example =
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ ( "baseFont", Fonts.baseFont )
|
||||
, ( "quizFont", Fonts.quizFont )
|
||||
, ( "ugFont", Fonts.ugFont )
|
||||
]
|
||||
|> List.map viewPreview
|
||||
, view =
|
||||
\_ ->
|
||||
[ Heading.h3 [] [ Html.text "baseFont" ]
|
||||
@ -48,3 +55,20 @@ example =
|
||||
[ Html.text "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" ]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
viewPreview : ( String, Style ) -> Html msg
|
||||
viewPreview ( name, font ) =
|
||||
Html.div
|
||||
[ css
|
||||
[ Css.displayFlex
|
||||
, Css.justifyContent Css.spaceBetween
|
||||
, font
|
||||
, Css.fontSize (Css.px 14)
|
||||
]
|
||||
]
|
||||
[ Html.p [ css [ Css.margin2 (Css.px 8) Css.zero ] ]
|
||||
[ Html.text name ]
|
||||
, Html.p [ css [ Css.margin2 (Css.px 8) Css.zero ] ]
|
||||
[ Html.text "AaBbCc" ]
|
||||
]
|
||||
|
@ -35,6 +35,12 @@ example =
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ Heading.h1 [] [ Html.text "h1" ]
|
||||
, Heading.h2 [] [ Html.text "h2" ]
|
||||
, Heading.h3 [] [ Html.text "h3" ]
|
||||
, Heading.h4 [] [ Html.text "h4" ]
|
||||
]
|
||||
, view =
|
||||
\_ ->
|
||||
[ Heading.h1 [] [ Html.text "This is the main page heading." ]
|
||||
|
@ -1,4 +1,4 @@
|
||||
module Examples.IconExamples exposing (view, viewWithCustomStyles)
|
||||
module Examples.IconExamples exposing (preview, view, viewWithCustomStyles)
|
||||
|
||||
import Css
|
||||
import Html.Styled as Html exposing (Html)
|
||||
@ -6,7 +6,24 @@ import Html.Styled.Attributes exposing (css, style, title)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
preview : List Svg.Svg -> List (Html msg)
|
||||
preview icons =
|
||||
[ Html.div
|
||||
[ css
|
||||
[ Css.displayFlex
|
||||
, Css.flexWrap Css.wrap
|
||||
, Css.property "gap" "10px"
|
||||
, Css.color Colors.gray45
|
||||
]
|
||||
]
|
||||
(List.map
|
||||
(Svg.withWidth (Css.px 30) >> Svg.withHeight (Css.px 30) >> Svg.toHtml)
|
||||
icons
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
view : String -> List ( String, Svg.Svg ) -> Html msg
|
||||
@ -55,5 +72,5 @@ viewIcon ( name, icon, style ) =
|
||||
]
|
||||
]
|
||||
[ Html.div [ css style ] [ Svg.toHtml icon ]
|
||||
, Text.smallBody [] [ Html.text name ]
|
||||
, Text.smallBody [ Text.plaintext name ]
|
||||
]
|
||||
|
@ -20,7 +20,7 @@ import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Loading.V1 as Loading
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -94,6 +94,7 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, preview = []
|
||||
, view =
|
||||
\{ showLoadingFadeIn, showLoading, showSpinners } ->
|
||||
[ if showLoading then
|
||||
@ -113,7 +114,7 @@ example =
|
||||
[ Loading.spinningPencil
|
||||
|> Svg.withColor Colors.azure
|
||||
|> Svg.toHtml
|
||||
, Text.caption [] [ Html.text "By default, the spinningPencil is white. Showing as blue for visibility." ]
|
||||
, Text.caption [ Text.plaintext "By default, the spinningPencil is white. Showing as blue for visibility." ]
|
||||
, Loading.spinningDots
|
||||
|> Svg.toHtml
|
||||
]
|
||||
|
@ -10,9 +10,12 @@ import Category exposing (Category(..))
|
||||
import Css
|
||||
import Example exposing (Example)
|
||||
import Examples.IconExamples as IconExamples
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Logo.V1 as Logo
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -35,6 +38,14 @@ example =
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
Html.div [ css [ Css.marginBottom (Css.px 8) ] ] [ Svg.toHtml Logo.noredink ]
|
||||
:: IconExamples.preview
|
||||
[ Logo.facebook
|
||||
, Logo.twitter
|
||||
, Logo.cleverC
|
||||
, Logo.googleG
|
||||
]
|
||||
, view =
|
||||
\_ ->
|
||||
[ IconExamples.viewWithCustomStyles "NRI"
|
||||
|
@ -47,6 +47,7 @@ example =
|
||||
}
|
||||
, { keys = [ Esc ], result = "Closes the menu" }
|
||||
]
|
||||
, preview = []
|
||||
, view = view
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import Category exposing (Category(..))
|
||||
import CommonControls
|
||||
import Css exposing (..)
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
import Example exposing (Example)
|
||||
import Html.Styled.Attributes as Attributes exposing (css, href)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
@ -14,6 +15,7 @@ import Nri.Ui.Message.V3 as Message
|
||||
import Nri.Ui.Pennant.V2 as Pennant
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import ViewHelpers exposing (viewExamples)
|
||||
|
||||
|
||||
type alias State =
|
||||
@ -26,26 +28,24 @@ init : State
|
||||
init =
|
||||
{ show = True
|
||||
, control =
|
||||
Control.record
|
||||
(\a b c d e f -> List.filterMap identity [ a, b, c, d, e, f ])
|
||||
|> Control.field "theme" controlTheme
|
||||
|> Control.field "content" (Control.map Just controlContent)
|
||||
|> Control.field "role" controlRole
|
||||
|> Control.field "dismissable" controlDismissable
|
||||
|> Control.field "css" controlCss
|
||||
|> Control.field "icon" controlIcon
|
||||
ControlExtra.list
|
||||
|> ControlExtra.optionalListItem "theme" controlTheme
|
||||
|> ControlExtra.listItem "content" controlContent
|
||||
|> ControlExtra.optionalListItem "role" controlRole
|
||||
|> ControlExtra.optionalListItem "dismissable" controlDismissable
|
||||
|> ControlExtra.optionalListItem "css" controlCss
|
||||
|> ControlExtra.optionalListItem "icon" controlIcon
|
||||
}
|
||||
|
||||
|
||||
controlTheme : Control (Maybe (Message.Attribute msg))
|
||||
controlTheme : Control (Message.Attribute msg)
|
||||
controlTheme =
|
||||
Control.choice
|
||||
[ ( "not set", Control.value Nothing )
|
||||
, ( "tip", Control.value (Just Message.tip) )
|
||||
, ( "error", Control.value (Just Message.error) )
|
||||
, ( "alert", Control.value (Just Message.alert) )
|
||||
, ( "success", Control.value (Just Message.success) )
|
||||
, ( "customTheme", Control.map Just controlCustomTheme )
|
||||
[ ( "tip", Control.value Message.tip )
|
||||
, ( "error", Control.value Message.error )
|
||||
, ( "alert", Control.value Message.alert )
|
||||
, ( "success", Control.value Message.success )
|
||||
, ( "customTheme", controlCustomTheme )
|
||||
]
|
||||
|
||||
|
||||
@ -64,13 +64,12 @@ controlCustomTheme =
|
||||
)
|
||||
|
||||
|
||||
controlIcon : Control (Maybe (Message.Attribute msg))
|
||||
controlIcon : Control (Message.Attribute msg)
|
||||
controlIcon =
|
||||
Control.choice
|
||||
[ ( "not set", Control.value Nothing )
|
||||
, ( "premiumFlag", Control.value (Just (Message.icon Pennant.premiumFlag)) )
|
||||
, ( "lock", Control.value (Just (Message.icon UiIcon.lock)) )
|
||||
, ( "clock", Control.value (Just (Message.icon UiIcon.clock)) )
|
||||
[ ( "premiumFlag", Control.value (Message.icon Pennant.premiumFlag) )
|
||||
, ( "lock", Control.value (Message.icon UiIcon.lock) )
|
||||
, ( "clock", Control.value (Message.icon UiIcon.clock) )
|
||||
]
|
||||
|
||||
|
||||
@ -123,37 +122,32 @@ controlContent =
|
||||
]
|
||||
|
||||
|
||||
controlRole : Control (Maybe (Message.Attribute msg))
|
||||
controlRole : Control (Message.Attribute msg)
|
||||
controlRole =
|
||||
Control.choice
|
||||
[ ( "not set", Control.value Nothing )
|
||||
, ( "alertRole", Control.value (Just Message.alertRole) )
|
||||
, ( "alertDialogRole", Control.value (Just Message.alertDialogRole) )
|
||||
[ ( "alertRole", Control.value Message.alertRole )
|
||||
, ( "alertDialogRole", Control.value Message.alertDialogRole )
|
||||
]
|
||||
|
||||
|
||||
controlDismissable : Control (Maybe (Message.Attribute Msg))
|
||||
controlDismissable : Control (Message.Attribute Msg)
|
||||
controlDismissable =
|
||||
Control.maybe False <|
|
||||
Control.value (Message.onDismiss Dismiss)
|
||||
Control.value (Message.onDismiss Dismiss)
|
||||
|
||||
|
||||
controlCss : Control (Maybe (Message.Attribute Msg))
|
||||
controlCss : Control (Message.Attribute Msg)
|
||||
controlCss =
|
||||
Control.choice
|
||||
[ ( "not set", Control.value Nothing )
|
||||
, ( "css [ border3 (px 1) dashed red ]"
|
||||
[ ( "css [ border3 (px 1) dashed red ]"
|
||||
, Control.value
|
||||
(Just (Message.css [ Css.border3 (Css.px 1) Css.dashed Colors.red ]))
|
||||
(Message.css [ Css.border3 (Css.px 1) Css.dashed Colors.red ])
|
||||
)
|
||||
, ( "css [ border3 (px 2) solid purple, borderRadius4 (px 8) (px 8) zero zero ]"
|
||||
, Control.value
|
||||
(Just
|
||||
(Message.css
|
||||
[ Css.border3 (Css.px 2) Css.solid Colors.purple
|
||||
, Css.borderRadius4 (Css.px 8) (Css.px 8) Css.zero Css.zero
|
||||
]
|
||||
)
|
||||
(Message.css
|
||||
[ Css.border3 (Css.px 2) Css.solid Colors.purple
|
||||
, Css.borderRadius4 (Css.px 8) (Css.px 8) Css.zero Css.zero
|
||||
]
|
||||
)
|
||||
)
|
||||
]
|
||||
@ -183,6 +177,11 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ Message.view [ Message.plaintext "Tiny tip" ]
|
||||
, Message.view [ Message.success, Message.plaintext "Tiny success" ]
|
||||
, Message.view [ Message.error, Message.plaintext "Tiny error" ]
|
||||
]
|
||||
, view =
|
||||
\state ->
|
||||
let
|
||||
@ -201,21 +200,10 @@ example =
|
||||
, Control.view UpdateControl state.control
|
||||
|> Html.fromUnstyled
|
||||
, orDismiss <|
|
||||
Html.table [ css [ width (pct 100) ] ]
|
||||
[ Html.tbody []
|
||||
[ tr []
|
||||
[ th [] [ Html.text "tiny" ]
|
||||
, td [] [ Message.view (Message.tiny :: attributes) ]
|
||||
]
|
||||
, tr []
|
||||
[ th [] [ Html.text "large" ]
|
||||
, td [] [ Message.view (Message.large :: attributes) ]
|
||||
]
|
||||
, tr []
|
||||
[ th [] [ Html.text "banner" ]
|
||||
, td [] [ Message.view (Message.banner :: attributes) ]
|
||||
]
|
||||
]
|
||||
viewExamples
|
||||
[ ( "tiny", Message.view (Message.tiny :: attributes) )
|
||||
, ( "large", Message.view (Message.large :: attributes) )
|
||||
, ( "banner", Message.view (Message.banner :: attributes) )
|
||||
]
|
||||
, Heading.h3
|
||||
[ Heading.css
|
||||
|
@ -7,21 +7,26 @@ module Examples.Modal exposing (Msg, State, example)
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html exposing (Html, div, h3, h4, p, span, text)
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Browser.Dom as Dom
|
||||
import Category exposing (Category(..))
|
||||
import Css exposing (..)
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
import Example exposing (Example)
|
||||
import Html as Root
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.Checkbox.V5 as Checkbox
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.Extra
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.FocusTrap.V1 as FocusTrap
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Modal.V11 as Modal
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Task
|
||||
|
||||
|
||||
@ -44,10 +49,10 @@ init =
|
||||
|
||||
controlAttributes : Control (List Modal.Attribute)
|
||||
controlAttributes =
|
||||
Control.record (\a b c -> a :: b :: c :: [])
|
||||
|> Control.field "Theme" controlTheme
|
||||
|> Control.field "Title visibility" controlTitleVisibility
|
||||
|> Control.field "Custom css" controlCss
|
||||
ControlExtra.list
|
||||
|> ControlExtra.listItem "Theme" controlTheme
|
||||
|> ControlExtra.listItem "Title visibility" controlTitleVisibility
|
||||
|> ControlExtra.listItem "Custom css" controlCss
|
||||
|
||||
|
||||
type alias ViewSettings =
|
||||
@ -124,6 +129,51 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, preview =
|
||||
[ -- faking a mini version of the Modal component to give styleguide users a sense of what the
|
||||
-- component might look like
|
||||
div
|
||||
[ css
|
||||
[ Css.backgroundColor (Nri.Ui.Colors.Extra.withAlpha 0.9 Colors.navy)
|
||||
, Css.borderRadius (Css.px 4)
|
||||
, Css.padding2 (Css.px 25) Css.zero
|
||||
, Css.displayFlex
|
||||
, Css.alignItems Css.center
|
||||
, Css.justifyContent Css.center
|
||||
]
|
||||
]
|
||||
[ div
|
||||
[ css
|
||||
[ Css.backgroundColor Colors.white
|
||||
, Css.padding (Css.px 10)
|
||||
, Css.borderRadius (Css.px 10)
|
||||
, Css.boxShadow5 Css.zero (Css.px 1) (Css.px 10) Css.zero (Css.rgba 0 0 0 0.35)
|
||||
, Css.textAlign Css.center
|
||||
, Css.color Colors.navy
|
||||
, Fonts.baseFont
|
||||
, Css.margin Css.auto
|
||||
, Css.width (Css.px 100)
|
||||
, Css.height (Css.px 60)
|
||||
, Css.fontSize (Css.px 10)
|
||||
, Css.fontWeight Css.bold
|
||||
, Css.position Css.relative
|
||||
]
|
||||
]
|
||||
[ text "Modal"
|
||||
, ClickableSvg.link "Close"
|
||||
UiIcon.x
|
||||
[ ClickableSvg.exactWidth 10
|
||||
, ClickableSvg.exactHeight 10
|
||||
, ClickableSvg.css
|
||||
[ Css.position absolute
|
||||
, Css.top (Css.px 10)
|
||||
, Css.right (Css.px 10)
|
||||
]
|
||||
, ClickableSvg.custom [ Key.tabbable False ]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
, view =
|
||||
\state ->
|
||||
let
|
||||
@ -228,7 +278,10 @@ launchModalButton settings =
|
||||
|
||||
viewModalContent : String -> Html msg
|
||||
viewModalContent content =
|
||||
Text.mediumBody [] [ span [ css [ whiteSpace preLine ] ] [ text content ] ]
|
||||
Text.mediumBody
|
||||
[ Text.css [ whiteSpace preLine ]
|
||||
, Text.plaintext content
|
||||
]
|
||||
|
||||
|
||||
continueButtonId : String
|
||||
@ -239,10 +292,9 @@ continueButtonId =
|
||||
continueButton : Html Msg
|
||||
continueButton =
|
||||
Button.button "Continue"
|
||||
[ Button.primary
|
||||
, Button.onClick CloseModal
|
||||
, Button.custom [ Attributes.id continueButtonId ]
|
||||
, Button.large
|
||||
[ Button.onClick CloseModal
|
||||
, Button.id continueButtonId
|
||||
, Button.modal
|
||||
]
|
||||
|
||||
|
||||
@ -255,9 +307,8 @@ closeClickableText : Html Msg
|
||||
closeClickableText =
|
||||
ClickableText.button "Close"
|
||||
[ ClickableText.onClick CloseModal
|
||||
, ClickableText.large
|
||||
, ClickableText.custom [ Attributes.id closeClickableTextId ]
|
||||
, ClickableText.css [ Css.marginTop (Css.px 15) ]
|
||||
, ClickableText.modal
|
||||
, ClickableText.id closeClickableTextId
|
||||
]
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@ import Html.Styled.Attributes exposing (css)
|
||||
import Http
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Page.V3 as Page exposing (RecoveryText(..))
|
||||
|
||||
@ -62,6 +63,32 @@ example =
|
||||
, state = { httpError = CommonControls.httpError, recoveryText = initRecoveryText }
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ -- faking a mini version of the Page component to give styleguide users a sense of what the
|
||||
-- component might look like
|
||||
Html.div
|
||||
[ css
|
||||
[ Css.displayFlex
|
||||
, Css.alignItems Css.center
|
||||
, Css.flexDirection Css.column
|
||||
, Css.backgroundColor Colors.white
|
||||
, Css.borderRadius (Css.px 4)
|
||||
, Css.padding (Css.px 20)
|
||||
]
|
||||
]
|
||||
[ Html.div [ css [ Css.fontSize (Css.px 40) ] ] [ Html.text "😵" ]
|
||||
, Html.p
|
||||
[ css
|
||||
[ Css.color Colors.navy
|
||||
, Fonts.baseFont
|
||||
, Css.fontWeight Css.bold
|
||||
, Css.textAlign Css.center
|
||||
, Css.margin Css.zero
|
||||
]
|
||||
]
|
||||
[ Html.text "There was a problem!" ]
|
||||
]
|
||||
]
|
||||
, view =
|
||||
\model ->
|
||||
let
|
||||
|
@ -38,6 +38,12 @@ example =
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
IconExamples.preview
|
||||
[ Pennant.premiumFlag
|
||||
, Pennant.expiredPremiumFlag
|
||||
, Pennant.disabledPremiumFlag
|
||||
]
|
||||
, view =
|
||||
\_ ->
|
||||
[ IconExamples.viewWithCustomStyles "Premium Pennants"
|
||||
|
@ -23,7 +23,7 @@ import Nri.Ui.Data.PremiumLevel as PremiumLevel exposing (PremiumLevel)
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Modal.V10 as Modal
|
||||
import Nri.Ui.RadioButton.V2 as RadioButton
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -34,6 +34,7 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, preview = []
|
||||
, view = view
|
||||
, categories = [ Inputs ]
|
||||
, keyboardSupport =
|
||||
@ -65,7 +66,7 @@ view model =
|
||||
Modal.MultipleFocusableElements
|
||||
(\{ firstFocusableElement, autofocusElement, lastFocusableElement, closeButton } ->
|
||||
{ content =
|
||||
[ Text.mediumBody [] [ text "Often, we'll launch a modal showing the benefits of premium when a locked radio button is clicked." ]
|
||||
[ Text.mediumBody [ Text.plaintext "Often, we'll launch a modal showing the benefits of premium when a locked radio button is clicked." ]
|
||||
, closeButton (autofocusElement :: firstFocusableElement)
|
||||
]
|
||||
, footer =
|
||||
|
@ -36,6 +36,7 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview = []
|
||||
, view =
|
||||
\state ->
|
||||
let
|
||||
|
@ -6,69 +6,71 @@ module Examples.Select exposing (Msg, State, example)
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Category exposing (Category(..))
|
||||
import Css
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
import Example exposing (Example)
|
||||
import Html.Styled
|
||||
import Html.Styled.Attributes
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Select.V7 as Select
|
||||
import Nri.Ui.Select.V8 as Select exposing (Choice)
|
||||
|
||||
|
||||
{-| -}
|
||||
example : Example State Msg
|
||||
example =
|
||||
{ name = "Select"
|
||||
, version = 7
|
||||
, version = 8
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, categories = [ Inputs ]
|
||||
, keyboardSupport = []
|
||||
, preview =
|
||||
[ Select.view "Label" [ Select.custom [ Key.tabbable False ] ]
|
||||
, Select.view "Hidden label"
|
||||
[ Select.hiddenLabel
|
||||
, Select.defaultDisplayText "Hidden label"
|
||||
, Select.custom [ Key.tabbable False ]
|
||||
]
|
||||
]
|
||||
, view =
|
||||
\state ->
|
||||
[ Html.Styled.label
|
||||
[ Html.Styled.Attributes.for "tortilla-selector" ]
|
||||
[ Heading.h3 [] [ Html.Styled.text "Tortilla Selector" ] ]
|
||||
, Select.view
|
||||
{ current = Nothing
|
||||
, choices =
|
||||
[ { label = "Tacos", value = "Tacos" }
|
||||
, { label = "Burritos", value = "Burritos" }
|
||||
, { label = "Enchiladas", value = "Enchiladas" }
|
||||
]
|
||||
, id = "tortilla-selector"
|
||||
, valueToString = identity
|
||||
, defaultDisplayText = Just "Select a tasty tortilla based treat!"
|
||||
, isInError = False
|
||||
}
|
||||
|> Html.Styled.map ConsoleLog
|
||||
, Html.Styled.label
|
||||
[ Html.Styled.Attributes.for "errored-selector" ]
|
||||
[ Heading.h3 [] [ Html.Styled.text "Errored Selector" ] ]
|
||||
, Select.view
|
||||
{ current = Nothing
|
||||
, choices = []
|
||||
, id = "errored-selector"
|
||||
, valueToString = identity
|
||||
, defaultDisplayText = Just "Please select an option"
|
||||
, isInError = True
|
||||
}
|
||||
|> Html.Styled.map ConsoleLog
|
||||
, Html.Styled.label
|
||||
[ Html.Styled.Attributes.for "overflowed-selector" ]
|
||||
[ Heading.h3 [] [ Html.Styled.text "Selector with Overflowed Text" ] ]
|
||||
let
|
||||
label =
|
||||
Control.currentValue state.label
|
||||
|
||||
( attributesCode, attributes ) =
|
||||
List.unzip (Control.currentValue state.attributes)
|
||||
in
|
||||
[ Control.view UpdateLabel state.label
|
||||
|> Html.Styled.fromUnstyled
|
||||
, Control.view UpdateAttributes state.attributes
|
||||
|> Html.Styled.fromUnstyled
|
||||
, Html.Styled.div
|
||||
[ Html.Styled.Attributes.css [ Css.maxWidth (Css.px 400) ] ]
|
||||
[ Select.view
|
||||
{ current = Nothing
|
||||
, choices = []
|
||||
, id = "overflowed-selector"
|
||||
, valueToString = identity
|
||||
, defaultDisplayText = Just "Look at me, I design coastlines, I got an award for Norway. Where's the sense in that?"
|
||||
, isInError = False
|
||||
}
|
||||
[ css [ Css.displayFlex, Css.alignItems Css.flexStart ]
|
||||
]
|
||||
[ Html.Styled.code
|
||||
[ css
|
||||
[ Css.display Css.block
|
||||
, Css.margin2 (Css.px 20) Css.zero
|
||||
, Css.whiteSpace Css.preWrap
|
||||
, Css.maxWidth (Css.px 500)
|
||||
]
|
||||
]
|
||||
[ Html.Styled.text <|
|
||||
"Select.view \""
|
||||
++ label
|
||||
++ "\""
|
||||
++ "\n [ "
|
||||
++ String.join "\n , " attributesCode
|
||||
++ "\n ] "
|
||||
]
|
||||
, Select.view label attributes
|
||||
|> Html.Styled.map ConsoleLog
|
||||
]
|
||||
]
|
||||
@ -76,19 +78,125 @@ example =
|
||||
|
||||
|
||||
{-| -}
|
||||
init : State
|
||||
init =
|
||||
Nothing
|
||||
type alias State =
|
||||
{ label : Control String
|
||||
, attributes : Control Settings
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias State =
|
||||
Maybe String
|
||||
init : State
|
||||
init =
|
||||
{ label = Control.string "Tortilla Selector"
|
||||
, attributes = initControls
|
||||
}
|
||||
|
||||
|
||||
type alias Settings =
|
||||
List ( String, Select.Attribute String )
|
||||
|
||||
|
||||
initControls : Control Settings
|
||||
initControls =
|
||||
ControlExtra.list
|
||||
|> ControlExtra.listItem "choices"
|
||||
(Control.map
|
||||
(\( code, choices ) ->
|
||||
( "Select.choices identity" ++ code
|
||||
, Select.choices identity choices
|
||||
)
|
||||
)
|
||||
initChoices
|
||||
)
|
||||
|> ControlExtra.optionalListItem "hiddenLabel"
|
||||
(Control.value ( "Select.hiddenLabel", Select.hiddenLabel ))
|
||||
|> ControlExtra.optionalListItem "defaultDisplayText"
|
||||
(Control.map
|
||||
(\str ->
|
||||
( "Select.defaultDisplayText \"" ++ str ++ "\""
|
||||
, Select.defaultDisplayText str
|
||||
)
|
||||
)
|
||||
(Control.string "Select a tasty tortilla based treat!")
|
||||
)
|
||||
|> ControlExtra.optionalListItem "containerCss"
|
||||
(Control.choice
|
||||
[ ( "flex-basis: 300px"
|
||||
, Control.value
|
||||
( "Select.containerCss [ Css.flexBasis (Css.px 300) ]"
|
||||
, Select.containerCss [ Css.flexBasis (Css.px 300) ]
|
||||
)
|
||||
)
|
||||
, ( "background-color: lichen"
|
||||
, Control.value
|
||||
( "Select.containerCss [ Css.backgroundColor Colors.lichen ]"
|
||||
, Select.containerCss [ Css.backgroundColor Colors.lichen ]
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
|> ControlExtra.optionalListItem "noMargin"
|
||||
(Control.map
|
||||
(\bool ->
|
||||
( "Select.noMargin " ++ Debug.toString bool
|
||||
, Select.noMargin bool
|
||||
)
|
||||
)
|
||||
(Control.bool True)
|
||||
)
|
||||
|> ControlExtra.optionalListItem "errorIf"
|
||||
(Control.map
|
||||
(\bool ->
|
||||
( "Select.errorIf " ++ Debug.toString bool
|
||||
, Select.errorIf bool
|
||||
)
|
||||
)
|
||||
(Control.bool True)
|
||||
)
|
||||
|> ControlExtra.optionalListItem "errorMessage"
|
||||
(Control.map
|
||||
(\str ->
|
||||
( "Select.errorMessage (Just \"" ++ str ++ "\")"
|
||||
, Select.errorMessage (Just str)
|
||||
)
|
||||
)
|
||||
(Control.string "The right item must be selected.")
|
||||
)
|
||||
|
||||
|
||||
initChoices : Control ( String, List (Choice String) )
|
||||
initChoices =
|
||||
Control.choice
|
||||
[ ( "Short choices"
|
||||
, ( """
|
||||
[ { label = "Tacos", value = "tacos" }
|
||||
, { label = "Burritos", value = "burritos" }
|
||||
, { label = "Enchiladas", value = "enchiladas" }
|
||||
]"""
|
||||
, [ { label = "Tacos", value = "tacos" }
|
||||
, { label = "Burritos", value = "burritos" }
|
||||
, { label = "Enchiladas", value = "enchiladas" }
|
||||
]
|
||||
)
|
||||
|> Control.value
|
||||
)
|
||||
, ( "Overflowing text choices"
|
||||
, ( """
|
||||
[ { label = "Look at me, I design coastlines, I got an award for Norway. Where's the sense in that? My mistress' eyes are nothing like the sun. Coral be far more red than her lips red.", value = "design-coastlines" }
|
||||
]"""
|
||||
, [ { label = "Look at me, I design coastlines, I got an award for Norway. Where's the sense in that? My mistress' eyes are nothing like the sun. Coral be far more red than her lips red.", value = "design-coastlines" }
|
||||
]
|
||||
)
|
||||
|> Control.value
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
type Msg
|
||||
= ConsoleLog String
|
||||
| UpdateLabel (Control String)
|
||||
| UpdateAttributes (Control Settings)
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -100,4 +208,14 @@ update msg state =
|
||||
_ =
|
||||
Debug.log "SelectExample" message
|
||||
in
|
||||
( Just message, Cmd.none )
|
||||
( state, Cmd.none )
|
||||
|
||||
UpdateLabel label ->
|
||||
( { state | label = label }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
UpdateAttributes attributes ->
|
||||
( { state | attributes = attributes }
|
||||
, Cmd.none
|
||||
)
|
||||
|
@ -42,6 +42,7 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview = []
|
||||
, view =
|
||||
\state ->
|
||||
[ Keyed.node "div"
|
||||
|
@ -40,6 +40,7 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview = []
|
||||
, view =
|
||||
\state ->
|
||||
[ viewModal state.modal
|
||||
|
@ -41,6 +41,7 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview = []
|
||||
, view =
|
||||
\{ sortState } ->
|
||||
let
|
||||
|
@ -17,7 +17,6 @@ import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Colors.Extra exposing (fromCssColor, toCssColor)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Select.V7 as Select
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import SolidColor exposing (SolidColor)
|
||||
@ -33,6 +32,7 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview = []
|
||||
, view =
|
||||
\state ->
|
||||
[ viewSettings state
|
||||
|
@ -6,12 +6,12 @@ module Examples.Switch exposing (Msg, State, example)
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Category
|
||||
import Example exposing (Example)
|
||||
import Html.Styled as Html
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Switch.V1 as Switch
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -31,40 +31,47 @@ example =
|
||||
, state = True
|
||||
, update = \(Switch new) _ -> ( new, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ Switch.view
|
||||
[ Switch.label (Html.text "Toggle On")
|
||||
, Switch.custom [ Key.tabbable False ]
|
||||
]
|
||||
False
|
||||
, Switch.view
|
||||
[ Switch.label (Html.text "Toggle Off")
|
||||
, Switch.custom [ Key.tabbable False ]
|
||||
]
|
||||
True
|
||||
]
|
||||
, view =
|
||||
\interactiveIsOn ->
|
||||
[ Heading.h3 [] [ Html.text "Interactive" ]
|
||||
, Text.mediumBody []
|
||||
[ Switch.view
|
||||
[ Switch.onSwitch Switch
|
||||
, Switch.id "switch-interactive"
|
||||
, Switch.label
|
||||
(if interactiveIsOn then
|
||||
Html.text "On"
|
||||
, Switch.view
|
||||
[ Switch.onSwitch Switch
|
||||
, Switch.id "switch-interactive"
|
||||
, Switch.label
|
||||
(if interactiveIsOn then
|
||||
Html.text "On"
|
||||
|
||||
else
|
||||
Html.text "Off"
|
||||
)
|
||||
]
|
||||
interactiveIsOn
|
||||
else
|
||||
Html.text "Off"
|
||||
)
|
||||
]
|
||||
, Heading.h3 [] [ Html.text "Disabled" ]
|
||||
, Text.mediumBody []
|
||||
[ Switch.view
|
||||
[ Switch.disabled
|
||||
, Switch.id "switch-disabled-on"
|
||||
, Switch.label (Html.text "Permanently on")
|
||||
]
|
||||
True
|
||||
interactiveIsOn
|
||||
, Heading.h3 [] [ Html.text "Disabled (On)" ]
|
||||
, Switch.view
|
||||
[ Switch.disabled
|
||||
, Switch.id "switch-disabled-on"
|
||||
, Switch.label (Html.text "Permanently on")
|
||||
]
|
||||
, Text.mediumBody []
|
||||
[ Switch.view
|
||||
[ Switch.disabled
|
||||
, Switch.id "switch-disabled-off"
|
||||
, Switch.label (Html.text "Permanently off")
|
||||
]
|
||||
False
|
||||
True
|
||||
, Heading.h3 [] [ Html.text "Disabled (Off)" ]
|
||||
, Switch.view
|
||||
[ Switch.disabled
|
||||
, Switch.id "switch-disabled-off"
|
||||
, Switch.label (Html.text "Permanently off")
|
||||
]
|
||||
False
|
||||
]
|
||||
, categories = [ Category.Inputs ]
|
||||
, keyboardSupport = [{- TODO -}]
|
||||
|
@ -37,6 +37,29 @@ example =
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, categories = [ Tables, Layout ]
|
||||
, keyboardSupport = []
|
||||
, preview =
|
||||
[ Table.view
|
||||
[ Table.string
|
||||
{ header = "A"
|
||||
, value = .a
|
||||
, width = px 50
|
||||
, cellStyles = always []
|
||||
}
|
||||
, Table.string
|
||||
{ header = "B"
|
||||
, value = .b
|
||||
, width = px 50
|
||||
, cellStyles = always []
|
||||
}
|
||||
]
|
||||
[ { a = "Row 1 A"
|
||||
, b = "Row 1 B"
|
||||
}
|
||||
, { a = "Row 2 A"
|
||||
, b = "Row 2 B"
|
||||
}
|
||||
]
|
||||
]
|
||||
, view =
|
||||
\() ->
|
||||
let
|
||||
|
@ -19,10 +19,13 @@ import Html.Styled as Html exposing (Html, fromUnstyled)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Key(..))
|
||||
import List.Zipper exposing (Zipper)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Tabs.V7 as Tabs exposing (Alignment(..), Tab)
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.Tooltip.V2 as Tooltip
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Routes
|
||||
import Task
|
||||
|
||||
|
||||
@ -117,9 +120,14 @@ update msg model =
|
||||
)
|
||||
|
||||
|
||||
exampleName : String
|
||||
exampleName =
|
||||
"Tabs"
|
||||
|
||||
|
||||
example : Example State Msg
|
||||
example =
|
||||
{ name = "Tabs"
|
||||
{ name = exampleName
|
||||
, version = 7
|
||||
, categories = [ Layout ]
|
||||
, keyboardSupport =
|
||||
@ -136,6 +144,49 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ -- faking a mini version of the Tabs component to give styleguide users a sense of what the
|
||||
-- component might look like
|
||||
Html.div [ css [ Css.displayFlex, Css.flexWrap Css.wrap ] ]
|
||||
[ Html.div
|
||||
[ css
|
||||
[ Css.backgroundColor Colors.white
|
||||
, Css.padding (Css.px 4)
|
||||
, Css.borderRadius4 (Css.px 4) (Css.px 4) Css.zero Css.zero
|
||||
, Css.border3 (Css.px 1) Css.solid Colors.navy
|
||||
, Css.borderBottomWidth Css.zero
|
||||
]
|
||||
]
|
||||
[ Text.smallBody [ Text.plaintext "Tab 1" ] ]
|
||||
, Html.div
|
||||
[ css [ Css.width (Css.px 4), Css.borderBottom3 (Css.px 1) Css.solid Colors.navy ]
|
||||
]
|
||||
[]
|
||||
, Html.div
|
||||
[ css
|
||||
[ Css.backgroundColor Colors.frost
|
||||
, Css.padding (Css.px 4)
|
||||
, Css.borderRadius4 (Css.px 4) (Css.px 4) Css.zero Css.zero
|
||||
, Css.border3 (Css.px 1) Css.solid Colors.navy
|
||||
]
|
||||
]
|
||||
[ Text.smallBody [ Text.plaintext "Tab 1" ] ]
|
||||
, Html.div
|
||||
[ css
|
||||
[ Css.width (Css.px 30)
|
||||
, Css.borderBottom3 (Css.px 1) Css.solid Colors.navy
|
||||
]
|
||||
]
|
||||
[]
|
||||
, Html.div
|
||||
[ css
|
||||
[ Css.paddingTop (Css.px 4)
|
||||
, Css.minWidth (Css.px 100)
|
||||
]
|
||||
]
|
||||
[ Text.caption [ Text.plaintext "Tab 1 content" ] ]
|
||||
]
|
||||
]
|
||||
, view =
|
||||
\model ->
|
||||
let
|
||||
@ -167,7 +218,7 @@ allTabs openTooltipId labelledBy =
|
||||
|> Svg.toHtml
|
||||
in
|
||||
[ Tabs.build { id = First, idString = "tab-0" }
|
||||
([ Tabs.spaHref "/#/doodad/Tabs"
|
||||
([ Tabs.spaHref <| Routes.toString (Routes.Doodad exampleName)
|
||||
, Tabs.tabString "1"
|
||||
, Tabs.withTooltip
|
||||
[ Tooltip.plaintext "Link Example"
|
||||
|
@ -7,79 +7,137 @@ module Examples.Text exposing (example, State, Msg)
|
||||
-}
|
||||
|
||||
import Category exposing (Category(..))
|
||||
import CommonControls exposing (exampleHtml, quickBrownFox, romeoAndJulietQuotation)
|
||||
import Css
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
import Example exposing (Example)
|
||||
import Html.Styled as Html
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias State =
|
||||
()
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias Msg =
|
||||
()
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
{-| -}
|
||||
example : Example State Msg
|
||||
example =
|
||||
{ name = "Text"
|
||||
, version = 5
|
||||
, version = 6
|
||||
, categories = [ Text ]
|
||||
, keyboardSupport = []
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ ( "caption", Text.caption )
|
||||
, ( "smallBody", Text.smallBody )
|
||||
, ( "mediumBody", Text.mediumBody )
|
||||
, ( "ugMediumBody", Text.ugMediumBody )
|
||||
]
|
||||
|> List.map viewPreview
|
||||
, view =
|
||||
\_ ->
|
||||
\state ->
|
||||
let
|
||||
exampleHtml kind =
|
||||
[ Html.text "This is a "
|
||||
, Html.strong [] [ Html.text kind ]
|
||||
, Html.text ". "
|
||||
, Html.a
|
||||
[ Attributes.href "http://www.noredink.com"
|
||||
, Attributes.target "_blank"
|
||||
]
|
||||
[ Html.text "The quick brown fox jumps over the lazy dog." ]
|
||||
, Html.text " Be on the lookout for a new and improved assignment creation form! Soon, you'll be able to easily see a summary of the content you're assigning, as well as an estimate for how long the assignment will take."
|
||||
]
|
||||
|
||||
exampleUGHtml kind =
|
||||
[ Html.text "This is a "
|
||||
, Html.strong [] [ Html.text kind ]
|
||||
, Html.text ". The quick brown fox jumps over the lazy dog."
|
||||
, Html.text " When I stepped out, into the bright sunlight from the darkness of the movie house, I had only two things on my mind: Paul Newman, and a ride home."
|
||||
]
|
||||
attributes =
|
||||
Control.currentValue state.control
|
||||
in
|
||||
[ Text.caption [] [ Html.text "NOTE: When using these styles, please read the documentation in the Elm module about \"Understanding spacing\"" ]
|
||||
[ Text.caption [ Text.plaintext "NOTE: When using these styles, please read the documentation in the Elm module about \"Understanding spacing\"" ]
|
||||
, Control.view UpdateControl state.control
|
||||
|> Html.fromUnstyled
|
||||
, Heading.h2 [ Heading.style Heading.Top ] [ Html.text "Paragraph styles" ]
|
||||
, Text.mediumBody [] (exampleHtml "mediumBody")
|
||||
, Text.smallBody [] (exampleHtml "smallBody")
|
||||
, Text.smallBodyGray [] (exampleHtml "smallBodyGray")
|
||||
, Text.caption [] (exampleHtml "caption")
|
||||
, viewExamples
|
||||
[ ( "mediumBody", Text.mediumBody )
|
||||
, ( "smallBody", Text.smallBody )
|
||||
, ( "smallBodyGray", Text.smallBodyGray )
|
||||
, ( "caption", Text.caption )
|
||||
]
|
||||
attributes
|
||||
, Heading.h2 [ Heading.style Heading.Top ] [ Html.text "Paragraph styles for user-authored content" ]
|
||||
, Text.ugMediumBody [] (exampleUGHtml "ugMediumBody")
|
||||
, Text.ugSmallBody [] (exampleUGHtml "ugSmallBody")
|
||||
, Heading.h2 [ Heading.style Heading.Top ] [ Html.text "One-Off Styles" ]
|
||||
, Text.mediumBody
|
||||
[ Text.css [ Css.padding (Css.px 20) ] ]
|
||||
[ Html.text "I've got more padding than my siblings!" ]
|
||||
, Html.div
|
||||
[ Attributes.css
|
||||
[ Css.width (Css.px 80)
|
||||
, Css.border3 (Css.px 1) Css.solid (Css.hex "000")
|
||||
]
|
||||
]
|
||||
[ Text.mediumBody
|
||||
[ Text.noBreak ]
|
||||
[ Html.text "I won't ever break, no matter how narrow my container is." ]
|
||||
, viewExamples
|
||||
[ ( "ugMediumBody", Text.ugMediumBody )
|
||||
, ( "ugSmallBody", Text.ugSmallBody )
|
||||
]
|
||||
attributes
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
viewPreview : ( String, List (Text.Attribute msg) -> Html msg ) -> Html msg
|
||||
viewPreview ( name, view ) =
|
||||
view [ Text.plaintext name ]
|
||||
|
||||
|
||||
viewExamples : List ( String, List (Text.Attribute msg) -> Html msg ) -> List (Text.Attribute msg) -> Html msg
|
||||
viewExamples examples attributes =
|
||||
let
|
||||
viewExample ( name, view ) =
|
||||
Html.tr []
|
||||
[ Html.th [] [ Html.text name ]
|
||||
, Html.td [] [ view attributes ]
|
||||
]
|
||||
in
|
||||
Html.table [ css [ Css.width (Css.pct 100) ] ]
|
||||
[ Html.tbody [] <|
|
||||
List.map viewExample examples
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias State =
|
||||
{ control : Control (List (Text.Attribute Msg))
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
init : State
|
||||
init =
|
||||
{ control =
|
||||
ControlExtra.list
|
||||
|> ControlExtra.listItem "content" controlContent
|
||||
|> ControlExtra.listItem "noBreak"
|
||||
(Control.map Text.noBreak (Control.bool False))
|
||||
|> ControlExtra.optionalListItem "css"
|
||||
(Control.value
|
||||
(Text.css
|
||||
[ Css.border3 (Css.px 1) Css.solid Colors.aqua
|
||||
, Css.color Colors.aquaDark
|
||||
]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
controlContent : Control (Text.Attribute msg)
|
||||
controlContent =
|
||||
Control.choice
|
||||
[ ( "HTML"
|
||||
, Control.value (Text.html exampleHtml)
|
||||
)
|
||||
, ( "plain text (short)"
|
||||
, Control.string quickBrownFox
|
||||
|> Control.map Text.plaintext
|
||||
)
|
||||
, ( "plain text (long)"
|
||||
, Control.stringTextarea romeoAndJulietQuotation
|
||||
|> Control.map Text.plaintext
|
||||
)
|
||||
, ( "markdown"
|
||||
, Control.string romeoAndJulietQuotation
|
||||
|> Control.map Text.markdown
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
type Msg
|
||||
= UpdateControl (Control (List (Text.Attribute Msg)))
|
||||
|
||||
|
||||
{-| -}
|
||||
update : Msg -> State -> ( State, Cmd Msg )
|
||||
update msg state =
|
||||
case msg of
|
||||
UpdateControl newControl ->
|
||||
( { state | control = newControl }, Cmd.none )
|
||||
|
@ -32,6 +32,7 @@ example =
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview = [ TextWriting.footnote [ text "This is a footnote. " ] ]
|
||||
, view =
|
||||
\_ ->
|
||||
let
|
||||
|
@ -44,6 +44,7 @@ example =
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, categories = [ Inputs ]
|
||||
, keyboardSupport = []
|
||||
, preview = []
|
||||
, view =
|
||||
\state ->
|
||||
[ Heading.h1 [] [ Html.text "Textarea controls" ]
|
||||
|
@ -7,9 +7,11 @@ module Examples.TextInput exposing (Msg, State, example)
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html exposing (..)
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Category exposing (Category(..))
|
||||
import Css exposing (..)
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
import Dict exposing (Dict)
|
||||
import Example exposing (Example)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
@ -17,259 +19,212 @@ import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Message.V3 as Message
|
||||
import Nri.Ui.TextInput.V6 as TextInput
|
||||
|
||||
|
||||
{-| -}
|
||||
type Msg
|
||||
= SetTextInput Id String
|
||||
| SetNumberInput (Maybe Int)
|
||||
| SetFloatInput (Maybe Float)
|
||||
| SetPassword String
|
||||
| SetSearchTerm String
|
||||
| UpdateControl (Control ExampleConfig)
|
||||
| HitEnter
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias State =
|
||||
{ numberInputValue : Maybe Int
|
||||
, floatInputValue : Maybe Float
|
||||
, stringInputValues : Dict Id String
|
||||
, passwordInputValue : String
|
||||
, searchInputValue : String
|
||||
, control : Control ExampleConfig
|
||||
, enterCount : Int
|
||||
}
|
||||
|
||||
|
||||
type alias ExampleConfig =
|
||||
{ label : String
|
||||
, maybePlaceholderAttribute : Maybe (TextInput.Attribute Msg)
|
||||
, maybeErrorAttribute1 : Maybe (TextInput.Attribute Msg)
|
||||
, maybeErrorAttribute2 : Maybe (TextInput.Attribute Msg)
|
||||
, maybeShowLabelAttribute : Maybe (TextInput.Attribute Msg)
|
||||
, maybeDisabledAttribute : Maybe (TextInput.Attribute Msg)
|
||||
, maybeLoadingAttribute : Maybe (TextInput.Attribute Msg)
|
||||
, noMarginAttribute : TextInput.Attribute Msg
|
||||
, onBlur : Bool
|
||||
, onReset : Bool
|
||||
}
|
||||
import Nri.Ui.TextInput.V7 as TextInput
|
||||
import ViewHelpers exposing (viewExamples)
|
||||
|
||||
|
||||
{-| -}
|
||||
example : Example State Msg
|
||||
example =
|
||||
{ name = "TextInput"
|
||||
, version = 6
|
||||
, version = 7
|
||||
, categories = [ Inputs ]
|
||||
, keyboardSupport = []
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ TextInput.view "Text Input"
|
||||
[ TextInput.custom [ Key.tabbable False ]
|
||||
]
|
||||
, TextInput.view "Errored"
|
||||
[ TextInput.value "invalid content"
|
||||
, TextInput.errorIf True
|
||||
, TextInput.custom [ Key.tabbable False ]
|
||||
]
|
||||
]
|
||||
, view =
|
||||
\state ->
|
||||
let
|
||||
exampleConfig =
|
||||
Control.currentValue state.control
|
||||
|
||||
attributes { setField, onBlur, onReset, onEnter } =
|
||||
List.filterMap identity
|
||||
[ exampleConfig.maybeErrorAttribute1
|
||||
, exampleConfig.maybeErrorAttribute2
|
||||
, exampleConfig.maybePlaceholderAttribute
|
||||
, exampleConfig.maybeShowLabelAttribute
|
||||
, exampleConfig.maybeDisabledAttribute
|
||||
, exampleConfig.maybeLoadingAttribute
|
||||
, Just exampleConfig.noMarginAttribute
|
||||
, if exampleConfig.onBlur then
|
||||
Just (TextInput.onBlur (setField onBlur))
|
||||
toExample { name, toString, inputType, onFocus, onBlur, onEnter } index =
|
||||
( name
|
||||
, TextInput.view exampleConfig.label
|
||||
(exampleConfig.attributes
|
||||
++ [ TextInput.id ("text-input__" ++ name ++ "-example")
|
||||
, inputType (toString >> SetInput index)
|
||||
|> TextInput.map toString identity
|
||||
, TextInput.value (Maybe.withDefault "" (Dict.get index state.inputValues))
|
||||
]
|
||||
++ List.filterMap identity
|
||||
[ if exampleConfig.onFocus then
|
||||
Just (TextInput.onFocus (SetInput index onFocus))
|
||||
|
||||
else
|
||||
Nothing
|
||||
, if exampleConfig.onReset then
|
||||
Just (TextInput.onReset (setField onReset))
|
||||
else
|
||||
Nothing
|
||||
, if exampleConfig.onBlur then
|
||||
Just (TextInput.onBlur (SetInput index onBlur))
|
||||
|
||||
else
|
||||
Nothing
|
||||
, Just <| TextInput.onEnter onEnter
|
||||
]
|
||||
else
|
||||
Nothing
|
||||
, if exampleConfig.onEnter then
|
||||
Just (TextInput.onEnter (SetInput index onEnter))
|
||||
|
||||
else
|
||||
Nothing
|
||||
]
|
||||
)
|
||||
)
|
||||
in
|
||||
[ Control.view UpdateControl state.control
|
||||
|> Html.fromUnstyled
|
||||
, Html.div
|
||||
[ css
|
||||
[ property "display" "grid"
|
||||
, property "grid-template-columns" "auto 1fr"
|
||||
, property "grid-gap" "10px"
|
||||
]
|
||||
]
|
||||
[ Heading.h3 [] [ text "TextInput.text" ]
|
||||
, TextInput.view (exampleConfig.label ++ " (text)")
|
||||
(TextInput.text (SetTextInput 1))
|
||||
(attributes
|
||||
{ setField = SetTextInput 1
|
||||
, onBlur = "Blurred!!!"
|
||||
, onReset = ""
|
||||
, onEnter = HitEnter
|
||||
}
|
||||
)
|
||||
(Maybe.withDefault "" <| Dict.get 1 state.stringInputValues)
|
||||
, Heading.h3 [] [ text "TextInput.number" ]
|
||||
, TextInput.view (exampleConfig.label ++ " (number)")
|
||||
(TextInput.number SetNumberInput)
|
||||
(TextInput.id "hey-this-is-a-test-id"
|
||||
:: attributes
|
||||
{ setField = SetNumberInput
|
||||
, onBlur = Just 10000000
|
||||
, onReset = Nothing
|
||||
, onEnter = HitEnter
|
||||
}
|
||||
)
|
||||
state.numberInputValue
|
||||
, Heading.h3 [] [ text "TextInput.float" ]
|
||||
, TextInput.view (exampleConfig.label ++ " (float)")
|
||||
(TextInput.float SetFloatInput)
|
||||
(attributes
|
||||
{ setField = SetFloatInput
|
||||
, onBlur = Just 1.00000001
|
||||
, onReset = Nothing
|
||||
, onEnter = HitEnter
|
||||
}
|
||||
)
|
||||
state.floatInputValue
|
||||
, Heading.h3 [] [ text "TextInput.password" ]
|
||||
, TextInput.view (exampleConfig.label ++ " (password)")
|
||||
(TextInput.password SetPassword)
|
||||
(attributes
|
||||
{ setField = SetPassword
|
||||
, onBlur = "Blurred!!!"
|
||||
, onReset = ""
|
||||
, onEnter = HitEnter
|
||||
}
|
||||
)
|
||||
state.passwordInputValue
|
||||
, Heading.h3 [] [ text "TextInput.email" ]
|
||||
, TextInput.view (exampleConfig.label ++ " (email)")
|
||||
(TextInput.email (SetTextInput 2))
|
||||
(attributes
|
||||
{ setField = SetTextInput 2
|
||||
, onBlur = "Blurred!!!"
|
||||
, onReset = ""
|
||||
, onEnter = HitEnter
|
||||
}
|
||||
)
|
||||
(Maybe.withDefault "" <| Dict.get 2 state.stringInputValues)
|
||||
, Heading.h3 [] [ Html.text "TextInput.writing" ]
|
||||
, TextInput.view (exampleConfig.label ++ " (writing)")
|
||||
(TextInput.text (SetTextInput 4))
|
||||
(TextInput.writing
|
||||
:: attributes
|
||||
{ setField = SetTextInput 4
|
||||
, onBlur = "Blurred!!!"
|
||||
, onReset = ""
|
||||
, onEnter = HitEnter
|
||||
}
|
||||
)
|
||||
(Maybe.withDefault "" <| Dict.get 4 state.stringInputValues)
|
||||
, Heading.h3 [] [ Html.text "TextInput.search" ]
|
||||
, TextInput.view (exampleConfig.label ++ " (search)")
|
||||
(TextInput.search SetSearchTerm)
|
||||
(attributes
|
||||
{ setField = SetSearchTerm
|
||||
, onBlur = "Blurred!!!"
|
||||
, onReset = ""
|
||||
, onEnter = HitEnter
|
||||
}
|
||||
)
|
||||
state.searchInputValue
|
||||
, Heading.h3 [] [ text "TextInput.css" ]
|
||||
, TextInput.view (exampleConfig.label ++ " (custom CSS)")
|
||||
(TextInput.text (SetTextInput 8))
|
||||
(TextInput.css [ Css.backgroundColor Colors.azure ]
|
||||
:: attributes
|
||||
{ setField = SetTextInput 8
|
||||
, onBlur = "Blurred!!!"
|
||||
, onReset = ""
|
||||
, onEnter = HitEnter
|
||||
}
|
||||
)
|
||||
(Maybe.withDefault "" <| Dict.get 8 state.stringInputValues)
|
||||
, Message.view
|
||||
[ Message.tiny
|
||||
, Message.tip
|
||||
, Message.plaintext <| "Hit enter " ++ String.fromInt state.enterCount ++ " times"
|
||||
]
|
||||
, (viewExamples << List.indexedMap (\i toView -> toView i))
|
||||
[ toExample
|
||||
{ name = "text"
|
||||
, toString = identity
|
||||
, inputType = TextInput.text
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "number"
|
||||
, toString = Maybe.map String.fromInt >> Maybe.withDefault ""
|
||||
, inputType = TextInput.number
|
||||
, onFocus = "1234"
|
||||
, onBlur = "10000000"
|
||||
, onEnter = "20000000"
|
||||
}
|
||||
, toExample
|
||||
{ name = "float"
|
||||
, toString = Maybe.map String.fromFloat >> Maybe.withDefault ""
|
||||
, inputType = TextInput.float
|
||||
, onFocus = "123"
|
||||
, onBlur = "1.00000001"
|
||||
, onEnter = "100000001.1"
|
||||
}
|
||||
, toExample
|
||||
{ name = "newPassword"
|
||||
, toString = identity
|
||||
, inputType =
|
||||
\onInput ->
|
||||
TextInput.newPassword
|
||||
{ onInput = onInput
|
||||
, showPassword = state.showPassword
|
||||
, setShowPassword = SetShowPassword
|
||||
}
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "email"
|
||||
, toString = identity
|
||||
, inputType = TextInput.email
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "search"
|
||||
, toString = identity
|
||||
, inputType = TextInput.search
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias State =
|
||||
{ inputValues : Dict Int String
|
||||
, showPassword : Bool
|
||||
, control : Control ExampleConfig
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
init : State
|
||||
init =
|
||||
{ numberInputValue = Nothing
|
||||
, floatInputValue = Nothing
|
||||
, stringInputValues = Dict.empty
|
||||
, passwordInputValue = ""
|
||||
, searchInputValue = ""
|
||||
, control =
|
||||
Control.record ExampleConfig
|
||||
|> Control.field "label" (Control.string "Assignment name")
|
||||
|> Control.field "TextInput.placeholder"
|
||||
(Control.maybe True <|
|
||||
Control.map TextInput.placeholder <|
|
||||
Control.string "Learning with commas"
|
||||
)
|
||||
|> Control.field "TextInput.hiddenLabel"
|
||||
(Control.maybe False (Control.value TextInput.hiddenLabel))
|
||||
|> Control.field "TextInput.errorIf"
|
||||
(Control.maybe False (Control.map TextInput.errorIf <| Control.bool True))
|
||||
|> Control.field "TextInput.errorMessage"
|
||||
(Control.maybe False (Control.map TextInput.errorMessage <| Control.maybe True <| Control.string "The statement must be true."))
|
||||
|> Control.field "TextInput.disabled"
|
||||
(Control.maybe False (Control.value TextInput.disabled))
|
||||
|> Control.field "TextInput.loading"
|
||||
(Control.maybe False (Control.value TextInput.loading))
|
||||
|> Control.field "TextInput.noMargin"
|
||||
(Control.map TextInput.noMargin (Control.bool False))
|
||||
|> Control.field "TextInput.onBlur"
|
||||
(Control.bool False)
|
||||
|> Control.field "TextInput.onReset"
|
||||
(Control.bool False)
|
||||
, enterCount = 0
|
||||
{ inputValues = Dict.empty
|
||||
, showPassword = False
|
||||
, control = initControl
|
||||
}
|
||||
|
||||
|
||||
type alias ExampleConfig =
|
||||
{ label : String
|
||||
, attributes : List (TextInput.Attribute String Msg)
|
||||
, onFocus : Bool
|
||||
, onBlur : Bool
|
||||
, onEnter : Bool
|
||||
}
|
||||
|
||||
|
||||
initControl : Control ExampleConfig
|
||||
initControl =
|
||||
Control.record ExampleConfig
|
||||
|> Control.field "label" (Control.string "Assignment name")
|
||||
|> Control.field "attributes" controlAttributes
|
||||
|> Control.field "onFocus" (Control.bool False)
|
||||
|> Control.field "onBlur" (Control.bool False)
|
||||
|> Control.field "onEnter" (Control.bool False)
|
||||
|
||||
|
||||
controlAttributes : Control (List (TextInput.Attribute value msg))
|
||||
controlAttributes =
|
||||
ControlExtra.list
|
||||
|> ControlExtra.optionalListItem "placeholder"
|
||||
(Control.map TextInput.placeholder <|
|
||||
Control.string "Learning with commas"
|
||||
)
|
||||
|> ControlExtra.optionalListItem "hiddenLabel"
|
||||
(Control.value TextInput.hiddenLabel)
|
||||
|> ControlExtra.optionalListItem "errorIf"
|
||||
(Control.map TextInput.errorIf <| Control.bool True)
|
||||
|> ControlExtra.optionalListItem "errorMessage"
|
||||
(Control.map (Just >> TextInput.errorMessage) <| Control.string "The statement must be true.")
|
||||
|> ControlExtra.optionalListItem "guidance"
|
||||
(Control.map TextInput.guidance <| Control.string "The statement must be true.")
|
||||
|> ControlExtra.optionalListItem "disabled"
|
||||
(Control.value TextInput.disabled)
|
||||
|> ControlExtra.optionalListItem "loading"
|
||||
(Control.value TextInput.loading)
|
||||
|> ControlExtra.optionalListItem "writing"
|
||||
(Control.value TextInput.writing)
|
||||
|> ControlExtra.listItem "noMargin"
|
||||
(Control.map TextInput.noMargin (Control.bool False))
|
||||
|> ControlExtra.optionalListItem "css"
|
||||
(Control.value (TextInput.css [ Css.backgroundColor Colors.azure ]))
|
||||
|
||||
|
||||
{-| -}
|
||||
type Msg
|
||||
= SetInput Int String
|
||||
| SetShowPassword Bool
|
||||
| UpdateControl (Control ExampleConfig)
|
||||
|
||||
|
||||
{-| -}
|
||||
update : Msg -> State -> ( State, Cmd Msg )
|
||||
update msg state =
|
||||
case msg of
|
||||
SetTextInput id textInputValue ->
|
||||
( { state | stringInputValues = Dict.insert id textInputValue state.stringInputValues }, Cmd.none )
|
||||
SetInput id string ->
|
||||
( { state | inputValues = Dict.insert id string state.inputValues }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
SetNumberInput numberInputValue ->
|
||||
( { state | numberInputValue = numberInputValue }, Cmd.none )
|
||||
|
||||
SetFloatInput floatInputValue ->
|
||||
( { state | floatInputValue = floatInputValue }, Cmd.none )
|
||||
|
||||
SetPassword password ->
|
||||
( { state | passwordInputValue = password }, Cmd.none )
|
||||
|
||||
SetSearchTerm searchInputValue ->
|
||||
( { state | searchInputValue = searchInputValue }, Cmd.none )
|
||||
SetShowPassword showPassword ->
|
||||
( { state | showPassword = showPassword }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
UpdateControl newControl ->
|
||||
( { state | control = newControl }, Cmd.none )
|
||||
|
||||
HitEnter ->
|
||||
( { state | enterCount = state.enterCount + 1 }, Cmd.none )
|
||||
|
||||
|
||||
|
||||
-- INTERNAL
|
||||
|
||||
|
||||
type alias Id =
|
||||
Int
|
||||
( { state | control = newControl }
|
||||
, Cmd.none
|
||||
)
|
||||
|
@ -7,9 +7,11 @@ module Examples.Tooltip exposing (example, State, Msg)
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html exposing (Html)
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Category exposing (Category(..))
|
||||
import Css
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
import Example exposing (Example)
|
||||
import Html.Styled.Attributes as Attributes exposing (css, href)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
@ -18,7 +20,7 @@ import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Text.V5 as Text
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.Tooltip.V2 as Tooltip
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
@ -32,13 +34,39 @@ example =
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ Html.div
|
||||
[ css
|
||||
[ Css.marginTop (Css.px 60)
|
||||
, Css.alignSelf Css.center
|
||||
]
|
||||
]
|
||||
[ Tooltip.view
|
||||
{ id = "preview-tooltip"
|
||||
, trigger =
|
||||
\attributes ->
|
||||
ClickableSvg.button "example-preview-tooltip-icon"
|
||||
UiIcon.gear
|
||||
[ ClickableSvg.custom attributes
|
||||
, ClickableSvg.small
|
||||
, ClickableSvg.custom [ Key.tabbable False ]
|
||||
]
|
||||
}
|
||||
[ Tooltip.plaintext "This is a tooltip."
|
||||
, Tooltip.open True
|
||||
, Tooltip.onTop
|
||||
, Tooltip.smallPadding
|
||||
, Tooltip.fitToContent
|
||||
]
|
||||
]
|
||||
]
|
||||
, view = view
|
||||
}
|
||||
|
||||
|
||||
type alias State =
|
||||
{ openTooltip : Maybe TooltipType
|
||||
, staticExampleSettings : Control ExampleSettings
|
||||
, staticExampleSettings : Control (List (Tooltip.Attribute Never))
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +85,7 @@ type TooltipType
|
||||
|
||||
type Msg
|
||||
= ToggleTooltip TooltipType Bool
|
||||
| SetStaticExampleSettings (Control ExampleSettings)
|
||||
| SetStaticExampleSettings (Control (List (Tooltip.Attribute Never)))
|
||||
|
||||
|
||||
update : Msg -> State -> ( State, Cmd Msg )
|
||||
@ -77,13 +105,15 @@ update msg model =
|
||||
view : State -> List (Html Msg)
|
||||
view model =
|
||||
[ Heading.h3 [] [ Html.text "Using the Tooltip module" ]
|
||||
, Text.mediumBody []
|
||||
[ Html.text "Label the Tooltip as either being the "
|
||||
, viewPrimaryLabelTooltip model.openTooltip
|
||||
, Html.text " or the "
|
||||
, viewAuxillaryDescriptionToolip model.openTooltip
|
||||
, Html.text " for the trigger content."
|
||||
, viewToggleTip model.openTooltip
|
||||
, Text.mediumBody
|
||||
[ Text.html
|
||||
[ Html.text "Label the Tooltip as either being the "
|
||||
, viewPrimaryLabelTooltip model.openTooltip
|
||||
, Html.text " or the "
|
||||
, viewAuxillaryDescriptionToolip model.openTooltip
|
||||
, Html.text " for the trigger content."
|
||||
, viewToggleTip model.openTooltip
|
||||
]
|
||||
]
|
||||
, viewCustomizableExample model.staticExampleSettings
|
||||
]
|
||||
@ -149,25 +179,15 @@ viewToggleTip openTooltip =
|
||||
]
|
||||
|
||||
|
||||
type alias ExampleSettings =
|
||||
{ content : Tooltip.Attribute Never
|
||||
, withoutTail : Bool
|
||||
, direction : Tooltip.Attribute Never
|
||||
, alignment : Tooltip.Attribute Never
|
||||
, width : Tooltip.Attribute Never
|
||||
, padding : Tooltip.Attribute Never
|
||||
}
|
||||
|
||||
|
||||
initStaticExampleSettings : Control ExampleSettings
|
||||
initStaticExampleSettings : Control (List (Tooltip.Attribute Never))
|
||||
initStaticExampleSettings =
|
||||
Control.record ExampleSettings
|
||||
|> Control.field "content" controlContent
|
||||
|> Control.field "withoutTail" controlTail
|
||||
|> Control.field "direction" controlDirection
|
||||
|> Control.field "alignment" controlAlignment
|
||||
|> Control.field "width" controlWidth
|
||||
|> Control.field "padding" controlPadding
|
||||
ControlExtra.list
|
||||
|> ControlExtra.listItem "content" controlContent
|
||||
|> ControlExtra.listItem "direction" controlDirection
|
||||
|> ControlExtra.listItem "alignment" controlAlignment
|
||||
|> ControlExtra.listItem "withoutTail" controlTail
|
||||
|> ControlExtra.listItem "width" controlWidth
|
||||
|> ControlExtra.listItem "padding" controlPadding
|
||||
|
||||
|
||||
controlContent : Control (Tooltip.Attribute Never)
|
||||
@ -206,9 +226,19 @@ controlContent =
|
||||
]
|
||||
|
||||
|
||||
controlTail : Control Bool
|
||||
controlTail : Control (Tooltip.Attribute Never)
|
||||
controlTail =
|
||||
Control.bool False
|
||||
Control.map
|
||||
(\bool ->
|
||||
if bool then
|
||||
Tooltip.withoutTail
|
||||
|
||||
else
|
||||
-- TODO: change `withoutTail` to take
|
||||
-- a bool or expose a `withTail` from Tooltip.
|
||||
Tooltip.css []
|
||||
)
|
||||
(Control.bool False)
|
||||
|
||||
|
||||
controlDirection : Control (Tooltip.Attribute Never)
|
||||
@ -253,26 +283,14 @@ controlPadding =
|
||||
]
|
||||
|
||||
|
||||
viewCustomizableExample : Control ExampleSettings -> Html Msg
|
||||
viewCustomizableExample : Control (List (Tooltip.Attribute Never)) -> Html Msg
|
||||
viewCustomizableExample controlSettings =
|
||||
let
|
||||
settings =
|
||||
Control.currentValue controlSettings
|
||||
|
||||
attributes =
|
||||
[ Tooltip.open True
|
||||
, settings.content
|
||||
, settings.direction
|
||||
, settings.alignment
|
||||
, settings.width
|
||||
, settings.padding
|
||||
]
|
||||
++ (if settings.withoutTail then
|
||||
[ Tooltip.withoutTail ]
|
||||
|
||||
else
|
||||
[]
|
||||
)
|
||||
Tooltip.open True :: settings
|
||||
in
|
||||
Html.div []
|
||||
[ Control.view SetStaticExampleSettings controlSettings
|
||||
|
@ -33,6 +33,21 @@ example =
|
||||
, state = ()
|
||||
, update = \_ state -> ( state, Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
IconExamples.preview
|
||||
[ UiIcon.seeMore
|
||||
, UiIcon.archive
|
||||
, UiIcon.share
|
||||
, UiIcon.footsteps
|
||||
, UiIcon.person
|
||||
, UiIcon.calendar
|
||||
, UiIcon.missingDocument
|
||||
, UiIcon.speechBalloon
|
||||
, UiIcon.edit
|
||||
, UiIcon.arrowTop
|
||||
, UiIcon.checkmark
|
||||
, UiIcon.equals
|
||||
]
|
||||
, view =
|
||||
\_ ->
|
||||
[ IconExamples.view "Interface"
|
||||
|
@ -1,6 +1,6 @@
|
||||
module Main exposing (init, main)
|
||||
|
||||
import Accessibility.Styled as Html exposing (Html, img, text)
|
||||
import Accessibility.Styled as Html exposing (Html)
|
||||
import Browser exposing (Document, UrlRequest(..))
|
||||
import Browser.Dom
|
||||
import Browser.Navigation exposing (Key)
|
||||
@ -10,15 +10,16 @@ import Css.Media exposing (withMedia)
|
||||
import Dict exposing (Dict)
|
||||
import Example exposing (Example)
|
||||
import Examples
|
||||
import Html as RootHtml
|
||||
import Html.Attributes
|
||||
import Html.Styled.Attributes as Attributes exposing (..)
|
||||
import Html.Styled.Events as Events
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.CssVendorPrefix.V1 as VendorPrefixed
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.MediaQuery.V1 exposing (mobile, notMobile)
|
||||
import Nri.Ui.Page.V3 as Page
|
||||
import Routes as Routes exposing (Route(..))
|
||||
import Sort.Set as Set exposing (Set)
|
||||
import Task
|
||||
@ -40,6 +41,7 @@ main =
|
||||
type alias Model =
|
||||
{ -- Global UI
|
||||
route : Route
|
||||
, previousRoute : Maybe Route
|
||||
, moduleStates : Dict String (Example Examples.State Examples.Msg)
|
||||
, navigationKey : Key
|
||||
}
|
||||
@ -48,6 +50,7 @@ type alias Model =
|
||||
init : () -> Url -> Key -> ( Model, Cmd Msg )
|
||||
init () url key =
|
||||
( { route = Routes.fromLocation url
|
||||
, previousRoute = Nothing
|
||||
, moduleStates =
|
||||
Dict.fromList
|
||||
(List.map (\example -> ( example.name, example )) Examples.all)
|
||||
@ -61,6 +64,7 @@ type Msg
|
||||
= UpdateModuleStates String Examples.Msg
|
||||
| OnUrlRequest Browser.UrlRequest
|
||||
| OnUrlChange Url
|
||||
| ChangeRoute Route
|
||||
| SkipToMainContent
|
||||
| NoOp
|
||||
|
||||
@ -95,7 +99,18 @@ update action model =
|
||||
( model, Browser.Navigation.load loc )
|
||||
|
||||
OnUrlChange route ->
|
||||
( { model | route = Routes.fromLocation route }, Cmd.none )
|
||||
( { model
|
||||
| route = Routes.fromLocation route
|
||||
, previousRoute = Just model.route
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
ChangeRoute route ->
|
||||
( model
|
||||
, Browser.Navigation.pushUrl model.navigationKey
|
||||
(Routes.toString route)
|
||||
)
|
||||
|
||||
SkipToMainContent ->
|
||||
( model
|
||||
@ -125,69 +140,86 @@ view_ model =
|
||||
let
|
||||
examples filterBy =
|
||||
List.filter (\m -> filterBy m) (Dict.values model.moduleStates)
|
||||
|
||||
mainContentHeader heading =
|
||||
Heading.h1
|
||||
[ Heading.customAttr (id "maincontent")
|
||||
, Heading.customAttr (tabindex -1)
|
||||
, Heading.css [ marginBottom (px 30) ]
|
||||
]
|
||||
[ Html.text heading ]
|
||||
in
|
||||
case model.route of
|
||||
Routes.Doodad doodad ->
|
||||
case List.head (examples (\m -> m.name == doodad)) of
|
||||
Just example ->
|
||||
Html.main_ []
|
||||
[ Example.view model.previousRoute example
|
||||
|> Html.map (UpdateModuleStates example.name)
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
Page.notFound
|
||||
{ link = ChangeRoute Routes.All
|
||||
, recoveryText = Page.ReturnTo "Component Library"
|
||||
}
|
||||
|
||||
Routes.Category category ->
|
||||
withSideNav model.route
|
||||
[ mainContentHeader (Category.forDisplay category)
|
||||
, examples
|
||||
(\doodad ->
|
||||
Set.memberOf
|
||||
(Set.fromList Category.sorter doodad.categories)
|
||||
category
|
||||
)
|
||||
|> viewPreviews (Category.forId category)
|
||||
]
|
||||
|
||||
Routes.All ->
|
||||
withSideNav model.route
|
||||
[ mainContentHeader "All"
|
||||
, viewPreviews "all" (examples (\_ -> True))
|
||||
]
|
||||
|
||||
|
||||
withSideNav : Route -> List (Html Msg) -> Html Msg
|
||||
withSideNav currentRoute content =
|
||||
Html.div
|
||||
[ css
|
||||
[ displayFlex
|
||||
, withMedia [ mobile ] [ flexDirection column, alignItems stretch ]
|
||||
, alignItems flexStart
|
||||
, minHeight (vh 100)
|
||||
]
|
||||
]
|
||||
[ navigation model.route
|
||||
, Html.main_ [ css [ flexGrow (int 1), sectionStyles ] ]
|
||||
(case model.route of
|
||||
Routes.Doodad doodad ->
|
||||
case List.head (examples (\m -> m.name == doodad)) of
|
||||
Just example ->
|
||||
[ mainContentHeader ("Viewing " ++ doodad ++ " doodad only")
|
||||
, Html.div [ id (String.replace "." "-" example.name) ]
|
||||
[ Example.view example
|
||||
|> Html.map (UpdateModuleStates example.name)
|
||||
]
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
[ Html.text <| "Oops! We couldn't find " ++ doodad ]
|
||||
|
||||
Routes.Category category ->
|
||||
[ mainContentHeader (Category.forDisplay category)
|
||||
, examples
|
||||
(\doodad ->
|
||||
Set.memberOf
|
||||
(Set.fromList Category.sorter doodad.categories)
|
||||
category
|
||||
)
|
||||
|> List.map
|
||||
(\example ->
|
||||
Example.view example
|
||||
|> Html.map (UpdateModuleStates example.name)
|
||||
)
|
||||
|> Html.div [ id (Category.forId category) ]
|
||||
]
|
||||
|
||||
Routes.All ->
|
||||
[ mainContentHeader "All"
|
||||
, examples (\_ -> True)
|
||||
|> List.map
|
||||
(\example ->
|
||||
Example.view example
|
||||
|> Html.map (UpdateModuleStates example.name)
|
||||
)
|
||||
|> Html.div []
|
||||
]
|
||||
)
|
||||
[ navigation currentRoute
|
||||
, Html.main_
|
||||
[ css
|
||||
[ flexGrow (int 1)
|
||||
, margin2 (px 40) zero
|
||||
, Css.minHeight (Css.vh 100)
|
||||
]
|
||||
]
|
||||
content
|
||||
]
|
||||
|
||||
|
||||
mainContentHeader : String -> Html msg
|
||||
mainContentHeader heading =
|
||||
Heading.h1
|
||||
[ Heading.customAttr (id "maincontent")
|
||||
, Heading.customAttr (tabindex -1)
|
||||
, Heading.css [ marginBottom (px 30) ]
|
||||
]
|
||||
[ Html.text heading ]
|
||||
|
||||
|
||||
viewPreviews : String -> List (Example state msg) -> Html Msg
|
||||
viewPreviews containerId examples =
|
||||
examples
|
||||
|> List.map (\example -> Example.preview ChangeRoute example)
|
||||
|> Html.div
|
||||
[ id containerId
|
||||
, css
|
||||
[ Css.displayFlex
|
||||
, Css.flexWrap Css.wrap
|
||||
, Css.property "gap" "10px"
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
navigation : Route -> Html Msg
|
||||
navigation route =
|
||||
let
|
||||
@ -200,31 +232,31 @@ navigation route =
|
||||
False
|
||||
|
||||
link active hash displayName =
|
||||
Html.a
|
||||
[ css
|
||||
[ backgroundColor transparent
|
||||
, borderStyle none
|
||||
, textDecoration none
|
||||
ClickableText.link displayName
|
||||
[ ClickableText.small
|
||||
, ClickableText.css
|
||||
[ Css.color Colors.navy
|
||||
, Css.display Css.block
|
||||
, Css.padding (Css.px 8)
|
||||
, Css.borderRadius (Css.px 8)
|
||||
, if active then
|
||||
color Colors.navy
|
||||
Css.backgroundColor Colors.glacier
|
||||
|
||||
else
|
||||
color Colors.azure
|
||||
, Fonts.baseFont
|
||||
Css.batch []
|
||||
]
|
||||
, Attributes.href hash
|
||||
, ClickableText.href hash
|
||||
]
|
||||
[ Html.text displayName ]
|
||||
|
||||
navLink category =
|
||||
link (isActive category)
|
||||
("#/category/" ++ Debug.toString category)
|
||||
(Routes.toString (Routes.Category category))
|
||||
(Category.forDisplay category)
|
||||
|
||||
toNavLi element =
|
||||
Html.li
|
||||
[ css
|
||||
[ margin2 (px 10) zero
|
||||
[ margin zero
|
||||
, listStyle none
|
||||
, textDecoration none
|
||||
]
|
||||
@ -269,18 +301,12 @@ navigation route =
|
||||
, id "skip"
|
||||
]
|
||||
[ Html.text "Skip to main content" ]
|
||||
, Heading.h4 [] [ Html.text "Categories" ]
|
||||
, (link (route == Routes.All) "#/" "All"
|
||||
:: List.map navLink Category.all
|
||||
)
|
||||
|> List.map toNavLi
|
||||
|> Html.ul
|
||||
[ css [ margin4 zero zero (px 40) zero, padding zero ]
|
||||
[ css [ margin zero, padding zero ]
|
||||
, id "categories"
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
sectionStyles : Css.Style
|
||||
sectionStyles =
|
||||
Css.batch [ margin2 (px 40) zero ]
|
||||
|
@ -1,4 +1,4 @@
|
||||
module Routes exposing (Route(..), fromLocation)
|
||||
module Routes exposing (Route(..), fromLocation, toString)
|
||||
|
||||
import Browser.Navigation as Navigation
|
||||
import Category
|
||||
@ -12,6 +12,19 @@ type Route
|
||||
| All
|
||||
|
||||
|
||||
toString : Route -> String
|
||||
toString route_ =
|
||||
case route_ of
|
||||
Doodad exampleName ->
|
||||
"#/doodad/" ++ exampleName
|
||||
|
||||
Category c ->
|
||||
"#/category/" ++ Debug.toString c
|
||||
|
||||
All ->
|
||||
"#/"
|
||||
|
||||
|
||||
route : Parser Route
|
||||
route =
|
||||
Parser.oneOf
|
||||
|
19
styleguide-app/ViewHelpers.elm
Normal file
19
styleguide-app/ViewHelpers.elm
Normal file
@ -0,0 +1,19 @@
|
||||
module ViewHelpers exposing (viewExamples)
|
||||
|
||||
import Css
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
|
||||
|
||||
viewExamples : List ( String, Html msg ) -> Html msg
|
||||
viewExamples examples =
|
||||
let
|
||||
viewExample ( name, view ) =
|
||||
Html.tr []
|
||||
[ Html.th [] [ Html.text name ]
|
||||
, Html.td [] [ view ]
|
||||
]
|
||||
in
|
||||
Html.table [ css [ Css.width (Css.pct 100) ] ]
|
||||
[ Html.tbody [] (List.map viewExample examples)
|
||||
]
|
@ -1,7 +1,7 @@
|
||||
module Spec.Nri.Ui.TextInput exposing (spec)
|
||||
|
||||
import Html.Styled
|
||||
import Nri.Ui.TextInput.V6 as TextInput
|
||||
import Nri.Ui.TextInput.V7 as TextInput
|
||||
import Test exposing (..)
|
||||
import Test.Html.Query as Query
|
||||
import Test.Html.Selector exposing (..)
|
||||
@ -9,13 +9,11 @@ import Test.Html.Selector exposing (..)
|
||||
|
||||
spec : Test
|
||||
spec =
|
||||
describe "Nri.Ui.TextInput.V6"
|
||||
describe "Nri.Ui.TextInput.V7"
|
||||
[ test "it uses the same DOM id that generateId produces" <|
|
||||
\() ->
|
||||
TextInput.view "myLabel"
|
||||
(TextInput.text identity)
|
||||
[]
|
||||
""
|
||||
[ TextInput.text identity ]
|
||||
|> Html.Styled.toUnstyled
|
||||
|> Query.fromHtml
|
||||
|> Query.has
|
||||
|
@ -47,6 +47,7 @@
|
||||
"Nri.Ui.SegmentedControl.V14",
|
||||
"Nri.Ui.Select.V5",
|
||||
"Nri.Ui.Select.V7",
|
||||
"Nri.Ui.Select.V8",
|
||||
"Nri.Ui.Slide.V1",
|
||||
"Nri.Ui.SlideModal.V2",
|
||||
"Nri.Ui.SortableTable.V2",
|
||||
@ -57,9 +58,11 @@
|
||||
"Nri.Ui.Tabs.V6",
|
||||
"Nri.Ui.Tabs.V7",
|
||||
"Nri.Ui.Text.V5",
|
||||
"Nri.Ui.Text.V6",
|
||||
"Nri.Ui.Text.Writing.V1",
|
||||
"Nri.Ui.TextArea.V4",
|
||||
"Nri.Ui.TextInput.V6",
|
||||
"Nri.Ui.TextInput.V7",
|
||||
"Nri.Ui.Tooltip.V1",
|
||||
"Nri.Ui.Tooltip.V2",
|
||||
"Nri.Ui.UiIcon.V1"
|
||||
|
Loading…
Reference in New Issue
Block a user